├── sample ├── .gitignore ├── keystore.jks ├── src │ └── main │ │ ├── res │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── values │ │ │ ├── colors.xml │ │ │ ├── styles.xml │ │ │ └── strings.xml │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ ├── layout │ │ │ └── activity_main.xml │ │ └── drawable │ │ │ └── ic_launcher_background.xml │ │ ├── java │ │ └── ru │ │ │ └── mail │ │ │ └── sdk │ │ │ └── sample │ │ │ ├── SampleApplication.kt │ │ │ └── MainActivity.kt │ │ └── AndroidManifest.xml ├── proguard-rules.pro └── build.gradle ├── sdk ├── .gitignore ├── gradle.properties ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── bools.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── styles.xml │ │ │ │ └── strings.xml │ │ │ ├── values-ru │ │ │ │ └── strings.xml │ │ │ └── layout │ │ │ │ └── webview_dialog.xml │ │ ├── java │ │ │ └── ru │ │ │ │ └── mail │ │ │ │ └── auth │ │ │ │ └── sdk │ │ │ │ ├── call │ │ │ │ ├── MethodCall.java │ │ │ │ ├── CallDecorator.java │ │ │ │ ├── NetworkErrorRetry.java │ │ │ │ ├── CallBuilder.java │ │ │ │ ├── RefreshTokenRetry.java │ │ │ │ ├── CallException.java │ │ │ │ └── BaseRetryMethodCall.java │ │ │ │ ├── browser │ │ │ │ ├── BrowserMatcher.java │ │ │ │ ├── BrowserRequestInitiator.java │ │ │ │ ├── VersionRange.java │ │ │ │ ├── DelimitedVersion.java │ │ │ │ ├── VersionedBrowserMatcher.java │ │ │ │ ├── BrowserDescriptor.java │ │ │ │ ├── Browsers.java │ │ │ │ └── BrowserSelector.java │ │ │ │ ├── api │ │ │ │ ├── ResponseProcessor.java │ │ │ │ ├── token │ │ │ │ │ ├── TokenExpiredListener.java │ │ │ │ │ ├── GrantType.java │ │ │ │ │ ├── OAuthTokensStorage.java │ │ │ │ │ ├── OAuthTokensResult.java │ │ │ │ │ ├── InMemoryTokensStorage.java │ │ │ │ │ ├── ExpiredTokenUpdater.java │ │ │ │ │ ├── RefreshAccessTokenRequest.java │ │ │ │ │ └── AccessTokenRequest.java │ │ │ │ ├── ApiMethod.java │ │ │ │ ├── user │ │ │ │ │ ├── UserInfoResult.java │ │ │ │ │ └── UserInfoRequest.java │ │ │ │ ├── OAuthRequestErrorCodes.java │ │ │ │ ├── CommonErrorCodes.java │ │ │ │ ├── BaseAuthResponseProcessor.java │ │ │ │ ├── ApiManager.java │ │ │ │ ├── ApiQuery.java │ │ │ │ └── ApiCommand.java │ │ │ │ ├── MailRuCallback.java │ │ │ │ ├── Analytics.java │ │ │ │ ├── RequestCodeOffset.java │ │ │ │ ├── StubAnalytics.java │ │ │ │ ├── AuthResult.java │ │ │ │ ├── RedirectReceiverActivity.java │ │ │ │ ├── AuthError.java │ │ │ │ ├── OAuthResponse.java │ │ │ │ ├── MRExecutors.java │ │ │ │ ├── OAuthRequest.java │ │ │ │ ├── OAuthParams.java │ │ │ │ ├── Utils.java │ │ │ │ ├── MailRuSdkServiceActivity.java │ │ │ │ ├── ui │ │ │ │ └── OAuthWebviewDialog.java │ │ │ │ └── MailRuAuthSdk.java │ │ └── AndroidManifest.xml │ └── test │ │ └── java │ │ ├── android │ │ └── util │ │ │ └── Log.java │ │ └── ru │ │ └── mail │ │ └── auth │ │ └── sdk │ │ └── call │ │ └── TestRetryCommand.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── .gitignore ├── docs └── app-example.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── LICENSE.txt ├── gradlew.bat ├── bintray.gradle ├── README.md ├── gradlew └── NOTICE.txt /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sdk/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':sample' 2 | include ':sdk' 3 | 4 | 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .idea 3 | local.properties 4 | *.iml 5 | .gradle 6 | -------------------------------------------------------------------------------- /sdk/gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableJetifier=true 2 | android.useAndroidX=true -------------------------------------------------------------------------------- /docs/app-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/docs/app-example.png -------------------------------------------------------------------------------- /sample/keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/sample/keystore.jks -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/sample/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/sample/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/sample/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sdk/src/main/res/values/bools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/sample/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/sample/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailru/mail-auth-sdk-android/master/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sdk/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ff005FF9 4 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/call/MethodCall.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.call; 2 | 3 | public interface MethodCall { 4 | R execute() throws CallException; 5 | } 6 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/browser/BrowserMatcher.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.browser; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | public interface BrowserMatcher { 6 | boolean matches(@NonNull BrowserDescriptor descriptor); 7 | } 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ff005FF9 4 | #0057e5 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/ResponseProcessor.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api; 2 | 3 | import ru.mail.auth.sdk.call.CallException; 4 | 5 | public interface ResponseProcessor { 6 | Result process(int code, String response) throws CallException; 7 | } 8 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/MailRuCallback.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | public interface MailRuCallback { 6 | 7 | void onResult(@NonNull Result result); 8 | 9 | void onError(@NonNull Error error); 10 | } 11 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/token/TokenExpiredListener.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api.token; 2 | 3 | import androidx.annotation.WorkerThread; 4 | import ru.mail.auth.sdk.call.CallException; 5 | 6 | public interface TokenExpiredListener { 7 | @WorkerThread 8 | void onTokenExpired() throws CallException; 9 | } 10 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/ApiMethod.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api; 2 | 3 | public enum ApiMethod { 4 | USERINFO("userinfo"), 5 | TOKEN("token"); 6 | 7 | private String mValue; 8 | 9 | ApiMethod(String value) { 10 | mValue = value; 11 | } 12 | 13 | public String getValue() { 14 | return mValue; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/Analytics.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | public interface Analytics { 6 | void onLoginStarted(@Nullable Type type); 7 | void onLoginSuccess(Type type); 8 | void onLoginFailed(Type type, String error); 9 | 10 | enum Type { 11 | WEB, 12 | APP 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/RequestCodeOffset.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk; 2 | 3 | enum RequestCodeOffset { 4 | LOGIN(1); 5 | 6 | private final int mCode; 7 | 8 | RequestCodeOffset(int code) { 9 | mCode = code; 10 | } 11 | 12 | int toRequestCode() { 13 | return MailRuAuthSdk.getInstance().getRequestCodeOffset() + mCode; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /sample/src/main/java/ru/mail/sdk/sample/SampleApplication.kt: -------------------------------------------------------------------------------- 1 | package ru.mail.sdk.sample 2 | 3 | import android.app.Application 4 | import ru.mail.auth.sdk.MailRuAuthSdk 5 | 6 | 7 | class SampleApplication: Application() { 8 | override fun onCreate() { 9 | super.onCreate() 10 | MailRuAuthSdk.initialize(this) 11 | MailRuAuthSdk.getInstance().isDebugEnabled = true 12 | } 13 | } -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/token/GrantType.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api.token; 2 | 3 | enum GrantType { 4 | AUTH_CODE("authorization_code"), 5 | REFRESH_TOKEN("refresh_token"); 6 | 7 | private String mValue; 8 | 9 | GrantType(String value) { 10 | mValue = value; 11 | } 12 | 13 | public String getValue() { 14 | return mValue; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/token/OAuthTokensStorage.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api.token; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | public interface OAuthTokensStorage { 6 | @Nullable 7 | String getAccessToken(); 8 | 9 | @Nullable 10 | String getRefreshToken(); 11 | 12 | void saveAccessToken(String token); 13 | 14 | void saveRefreshToken(String token); 15 | } 16 | -------------------------------------------------------------------------------- /sdk/src/main/res/values-ru/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Доступ запрещен 4 | Операция отменена 5 | Ошибка сети 6 | через Почту 7 | Войти как %s 8 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/call/CallDecorator.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.call; 2 | 3 | public class CallDecorator implements MethodCall { 4 | 5 | private final MethodCall mDecorated; 6 | 7 | public CallDecorator(MethodCall decorated) { 8 | mDecorated = decorated; 9 | } 10 | 11 | @Override 12 | public R execute() throws CallException { 13 | return mDecorated.execute(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /sample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/StubAnalytics.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | public class StubAnalytics implements Analytics { 6 | @Override 7 | public void onLoginStarted(@Nullable Type type) { 8 | /* no op */ 9 | } 10 | 11 | @Override 12 | public void onLoginSuccess(Type type) { 13 | /* no op */ 14 | } 15 | 16 | @Override 17 | public void onLoginFailed(Type type, String error) { 18 | /* no op */ 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Sdk Sample 3 | https://o2.mail.ru/login 4 | userinfo 5 | f77f3e3c1cd142adab5971b7d096e5b6 6 | ru.mail.sdk.sample://oauth2redirect 7 | Network error 8 | 9 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/token/OAuthTokensResult.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api.token; 2 | 3 | public class OAuthTokensResult { 4 | private final String mAccessToken; 5 | private final String mRefreshToken; 6 | 7 | public OAuthTokensResult(String accessToken, String refreshToken) { 8 | mAccessToken = accessToken; 9 | mRefreshToken = refreshToken; 10 | } 11 | 12 | public String getRefreshToken() { 13 | return mRefreshToken; 14 | } 15 | 16 | public String getAccessToken() { 17 | return mAccessToken; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/AuthResult.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | 6 | public class AuthResult { 7 | @NonNull 8 | private final String mAuthCode; 9 | 10 | @Nullable 11 | private final String mCodeVerifier; 12 | 13 | public AuthResult(@NonNull String code, @Nullable String codeVerifier) { 14 | mAuthCode = code; 15 | mCodeVerifier = codeVerifier; 16 | } 17 | 18 | @NonNull 19 | public String getAuthCode() { 20 | return mAuthCode; 21 | } 22 | 23 | @Nullable 24 | public String getCodeVerifier() { 25 | return mCodeVerifier; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sdk/src/test/java/android/util/Log.java: -------------------------------------------------------------------------------- 1 | package android.util; 2 | 3 | public class Log { 4 | public static int d(String tag, String msg) { 5 | System.out.println("DEBUG: " + tag + ": " + msg); 6 | return 0; 7 | } 8 | 9 | public static int i(String tag, String msg) { 10 | System.out.println("INFO: " + tag + ": " + msg); 11 | return 0; 12 | } 13 | 14 | public static int w(String tag, String msg) { 15 | System.out.println("WARN: " + tag + ": " + msg); 16 | return 0; 17 | } 18 | 19 | public static int e(String tag, String msg) { 20 | System.out.println("ERROR: " + tag + ": " + msg); 21 | return 0; 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/user/UserInfoResult.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api.user; 2 | 3 | public class UserInfoResult { 4 | private String mName; 5 | private String mAvatarUrl; 6 | private String mEmail; 7 | private String mMailID; 8 | 9 | public UserInfoResult(String name, String avatarUrl, String email, String mailID) { 10 | mName = name; 11 | mAvatarUrl = avatarUrl; 12 | mEmail = email; 13 | mMailID = mailID; 14 | } 15 | 16 | public String getName() { 17 | return mName; 18 | } 19 | 20 | public String getAvatarUrl() { 21 | return mAvatarUrl; 22 | } 23 | 24 | public String getEmail() { 25 | return mEmail; 26 | } 27 | 28 | public String getMailID() { 29 | return mMailID; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sdk/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/call/NetworkErrorRetry.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.call; 2 | 3 | public class NetworkErrorRetry extends BaseRetryMethodCall { 4 | 5 | private static final int NETWORK_ERROR_RETRY = 3; 6 | 7 | public NetworkErrorRetry(MethodCall decorated, int amount) { 8 | super(decorated, amount); 9 | } 10 | 11 | public NetworkErrorRetry(MethodCall decorated) { 12 | super(decorated, NETWORK_ERROR_RETRY); 13 | } 14 | 15 | @Override 16 | protected boolean shouldDelayBeforeRetry() { 17 | return true; 18 | } 19 | 20 | @Override 21 | protected String getNameForLog() { 22 | return "NetworkRetry"; 23 | } 24 | 25 | protected boolean handleException(CallException e) { 26 | return e.isNetworkError() || e.isInternalServerError(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sdk/src/main/res/layout/webview_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 21 | -------------------------------------------------------------------------------- /sdk/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -keep class ru.mail.auth.sdk.OAuthParams {*;} 23 | -------------------------------------------------------------------------------- /sdk/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MailRuAuthSdk 3 | https://o2.mail.ru/login 4 | userinfo 5 | your_client_id 6 | https://your_callback 7 | 8 | There was a network error 9 | Operation was cancelled 10 | Access denied 11 | MailRu Icon 12 | with MailRu 13 | Login as %s 14 | 15 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/OAuthRequestErrorCodes.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api; 2 | 3 | public class OAuthRequestErrorCodes extends CommonErrorCodes { 4 | public static final int INVALID_CLIENT_ID = 1; 5 | public static final int INVALID_REQUEST = 2; 6 | public static final int INVALID_CREDENTIALS = 3; 7 | public static final int INVALID_TOKEN = 6; 8 | 9 | public static String toReadableString(int code) { 10 | switch (code) { 11 | case INVALID_CLIENT_ID: 12 | return "Invalid client id"; 13 | case INVALID_REQUEST: 14 | return "Invalid request"; 15 | case INVALID_TOKEN: 16 | return "Invalid credentials"; 17 | case INVALID_CREDENTIALS: 18 | return "Invalid token"; 19 | default: 20 | return CommonErrorCodes.toReadableString(code); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sdk/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | ext.publication = true 4 | 5 | android { 6 | compileSdkVersion 29 7 | 8 | defaultConfig { 9 | minSdkVersion 16 10 | targetSdkVersion 29 11 | versionCode 1 12 | versionName "1.0" 13 | consumerProguardFiles 'proguard-rules.pro' 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | repositories { 27 | google() 28 | } 29 | 30 | dependencies { 31 | implementation fileTree(dir: 'libs', include: ['*.jar']) 32 | implementation 'androidx.appcompat:appcompat:1.1.0' 33 | implementation 'androidx.browser:browser:1.0.0' 34 | testImplementation 'junit:junit:4.12' 35 | } 36 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/call/CallBuilder.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.call; 2 | 3 | import ru.mail.auth.sdk.api.token.TokenExpiredListener; 4 | 5 | public class CallBuilder { 6 | private MethodCall mCall; 7 | 8 | private CallBuilder(MethodCall call) { 9 | mCall = call; 10 | } 11 | 12 | public static CallBuilder from(MethodCall call) { 13 | return new CallBuilder<>(call); 14 | } 15 | 16 | public CallBuilder withNetworkRetry() { 17 | mCall = new NetworkErrorRetry<>(mCall); 18 | return this; 19 | } 20 | 21 | public CallBuilder withNetworkRetry(int retryAmount) { 22 | mCall = new NetworkErrorRetry<>(mCall, retryAmount); 23 | return this; 24 | } 25 | 26 | public CallBuilder withAccessTokenRefresh(TokenExpiredListener listener) { 27 | mCall = new RefreshTokenRetry<>(mCall, listener); 28 | return this; 29 | } 30 | 31 | public MethodCall build() { 32 | return mCall; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/CommonErrorCodes.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api; 2 | 3 | public class CommonErrorCodes { 4 | public static final int NETWORK_ERROR = -1; 5 | public static final int SERVER_API_ERROR = -2; 6 | public static final int MALFORMED_URL_ERROR = -3; 7 | public static final int RETRY_LIMIT_EXCEEDED = -4; 8 | public static final int REQUEST_CANCELLED = -5; 9 | 10 | public static String toReadableString(int code) { 11 | switch (code) { 12 | case NETWORK_ERROR: 13 | return "Network error"; 14 | case SERVER_API_ERROR: 15 | return "Server api error"; 16 | case MALFORMED_URL_ERROR: 17 | return "Malformed url error"; 18 | case RETRY_LIMIT_EXCEEDED: 19 | return "Network retry limit exceeded"; 20 | case REQUEST_CANCELLED: 21 | return "Request cancelled"; 22 | default: 23 | return "Unknown error"; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/token/InMemoryTokensStorage.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api.token; 2 | 3 | import androidx.annotation.Nullable; 4 | import ru.mail.auth.sdk.api.token.OAuthTokensStorage; 5 | 6 | public class InMemoryTokensStorage implements OAuthTokensStorage { 7 | 8 | private String mAccessToken; 9 | private String mRefreshToken; 10 | 11 | public InMemoryTokensStorage(String accessToken, String refreshToken) { 12 | mAccessToken = accessToken; 13 | mRefreshToken = refreshToken; 14 | } 15 | 16 | @Nullable 17 | @Override 18 | public String getAccessToken() { 19 | return mAccessToken; 20 | } 21 | 22 | @Nullable 23 | @Override 24 | public String getRefreshToken() { 25 | return mRefreshToken; 26 | } 27 | 28 | @Override 29 | public void saveAccessToken(String token) { 30 | mAccessToken = token; 31 | } 32 | 33 | @Override 34 | public void saveRefreshToken(String token) { 35 | mRefreshToken = token; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/RedirectReceiverActivity.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import androidx.annotation.Nullable; 8 | 9 | public class RedirectReceiverActivity extends Activity{ 10 | 11 | public static final String EXTRA_URI = "extra_uri"; 12 | 13 | @Override 14 | protected void onCreate(@Nullable Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | startActivity(createResponseHandlingIntent()); 17 | finish(); 18 | } 19 | 20 | private Intent createResponseHandlingIntent() { 21 | Uri uri = getIntent().getData(); 22 | Intent intent = new Intent(this, MailRuSdkServiceActivity.class); 23 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP 24 | | Intent.FLAG_ACTIVITY_SINGLE_TOP 25 | | Intent.FLAG_ACTIVITY_NEW_TASK); 26 | intent.putExtra(EXTRA_URI, uri); 27 | return intent; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/BaseAuthResponseProcessor.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | import ru.mail.auth.sdk.call.CallException; 7 | 8 | public abstract class BaseAuthResponseProcessor implements ResponseProcessor { 9 | @Override 10 | public final T process(int code, String response) throws CallException { 11 | try { 12 | JSONObject jsonObject = new JSONObject(response); 13 | if (jsonObject.has("error")) { 14 | int errorCode = jsonObject.getInt("error_code"); 15 | throw new CallException(errorCode, jsonObject.optString("error_description")); 16 | } else { 17 | return processOkResult(jsonObject); 18 | } 19 | } catch (JSONException e) { 20 | throw new CallException(CommonErrorCodes.SERVER_API_ERROR, e.getMessage()); 21 | } 22 | } 23 | 24 | protected abstract T processOkResult(JSONObject jsonObject) throws JSONException; 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Mail.ru Group 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/token/ExpiredTokenUpdater.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api.token; 2 | 3 | import ru.mail.auth.sdk.OAuthParams; 4 | import ru.mail.auth.sdk.api.ApiManager; 5 | import ru.mail.auth.sdk.call.CallException; 6 | import ru.mail.auth.sdk.call.MethodCall; 7 | 8 | public class ExpiredTokenUpdater implements TokenExpiredListener { 9 | 10 | private final OAuthTokensStorage mOAuthTokensStorage; 11 | private final OAuthParams mOAuthParams; 12 | 13 | public ExpiredTokenUpdater(OAuthTokensStorage oAuthTokensStorage, OAuthParams oAuthParams) { 14 | mOAuthTokensStorage = oAuthTokensStorage; 15 | mOAuthParams = oAuthParams; 16 | } 17 | 18 | @Override 19 | public void onTokenExpired() throws CallException { 20 | MethodCall call = ApiManager.getRefreshAccessTokenCall( 21 | mOAuthParams.getClientId(), 22 | mOAuthTokensStorage.getRefreshToken() 23 | ); 24 | OAuthTokensResult result = call.execute(); 25 | mOAuthTokensStorage.saveAccessToken(result.getAccessToken()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/AuthError.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk; 2 | 3 | import androidx.annotation.StringRes; 4 | 5 | import ru.mail.auth.sdk.pub.R; 6 | 7 | public enum AuthError { 8 | NETWORK_ERROR(MailRuAuthSdk.STATUS_ERROR, R.string.mailru_oauth_network_error), 9 | USER_CANCELLED(MailRuAuthSdk.STATUS_CANCELLED, R.string.mailru_oauth_user_cancelled), 10 | ACCESS_DENIED(MailRuAuthSdk.STATUS_ACCESS_DENIED, R.string.mailru_oauth_user_denied); 11 | 12 | private int mStatusCode; 13 | private @StringRes int mRepresentation; 14 | 15 | AuthError(int statusCode, int representation) { 16 | mStatusCode = statusCode; 17 | mRepresentation = representation; 18 | } 19 | 20 | public String getErrorReason() { 21 | return MailRuAuthSdk.getInstance().getContext().getString(mRepresentation); 22 | } 23 | 24 | static AuthError fromCode(int statusCode) { 25 | for (AuthError authError : values()) { 26 | if (authError.mStatusCode == statusCode) { 27 | return authError; 28 | } 29 | } 30 | throw new IllegalStateException("Unknown error code " + statusCode); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/call/RefreshTokenRetry.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.call; 2 | 3 | import androidx.annotation.NonNull; 4 | import ru.mail.auth.sdk.api.token.TokenExpiredListener; 5 | 6 | public class RefreshTokenRetry extends BaseRetryMethodCall { 7 | 8 | public static final int RETRY_CNT = 1; 9 | 10 | @NonNull 11 | private final TokenExpiredListener mRefreshTokenListener; 12 | 13 | public RefreshTokenRetry(MethodCall decorated, 14 | @NonNull TokenExpiredListener refreshTokenListener) { 15 | super(decorated, RETRY_CNT); 16 | mRefreshTokenListener = refreshTokenListener; 17 | } 18 | 19 | @Override 20 | protected String getNameForLog() { 21 | return "RefreshTokenRetry"; 22 | } 23 | 24 | @Override 25 | protected boolean handleException(CallException e) throws CallException { 26 | if (e.isRecoverableAuthError()) { 27 | mRefreshTokenListener.onTokenExpired(); 28 | return true; 29 | } 30 | return false; 31 | } 32 | 33 | @Override 34 | protected boolean shouldDelayBeforeRetry() { 35 | return false; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /sdk/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/OAuthResponse.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk; 2 | 3 | import android.net.Uri; 4 | import androidx.annotation.Nullable; 5 | import android.text.TextUtils; 6 | 7 | public class OAuthResponse { 8 | private int mStatus; 9 | private String mResult; 10 | 11 | private OAuthResponse(int code, String result) { 12 | mStatus = code; 13 | mResult = result; 14 | } 15 | 16 | public static OAuthResponse from(OAuthRequest request, @Nullable Uri redirectResponse) { 17 | String queryParam; 18 | if (redirectResponse == null) { 19 | return new OAuthResponse(MailRuAuthSdk.STATUS_CANCELLED, null); 20 | } else if ((queryParam = redirectResponse.getQueryParameter("code")) != null 21 | && TextUtils.equals(request.getState(), redirectResponse.getQueryParameter("state"))) { 22 | return new OAuthResponse(MailRuAuthSdk.STATUS_OK, queryParam); 23 | } else if ((queryParam = redirectResponse.getQueryParameter("error")) != null) { 24 | if (TextUtils.equals(queryParam, "access_denied")) { 25 | return new OAuthResponse(MailRuAuthSdk.STATUS_ACCESS_DENIED, null); 26 | } else { 27 | return new OAuthResponse(MailRuAuthSdk.STATUS_ERROR, queryParam); 28 | } 29 | } else { 30 | return new OAuthResponse(MailRuAuthSdk.STATUS_ERROR, null); 31 | } 32 | } 33 | 34 | public int getResultCode() { 35 | return mStatus; 36 | } 37 | 38 | public String getResult() { 39 | return mResult; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/user/UserInfoRequest.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api.user; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | import ru.mail.auth.sdk.api.ApiCommand; 7 | import ru.mail.auth.sdk.api.ApiMethod; 8 | import ru.mail.auth.sdk.api.ApiQuery; 9 | import ru.mail.auth.sdk.api.BaseAuthResponseProcessor; 10 | import ru.mail.auth.sdk.api.token.OAuthTokensStorage; 11 | import ru.mail.auth.sdk.api.ResponseProcessor; 12 | 13 | public class UserInfoRequest extends ApiCommand { 14 | private OAuthTokensStorage mProvider; 15 | 16 | public UserInfoRequest(OAuthTokensStorage provider) { 17 | mProvider = provider; 18 | } 19 | 20 | @Override 21 | protected ApiQuery getQuery() { 22 | return new ApiQuery.Builder() 23 | .withHost(ApiCommand.O2_API_HOST) 24 | .withMethodName(ApiMethod.USERINFO.getValue()) 25 | .withPostParam("access_token", mProvider.getAccessToken()) 26 | .build(); 27 | } 28 | 29 | @Override 30 | protected ResponseProcessor getResponseProcessor() { 31 | return new Processor(); 32 | } 33 | 34 | private static class Processor extends BaseAuthResponseProcessor { 35 | 36 | @Override 37 | protected UserInfoResult processOkResult(JSONObject jsonObject) throws JSONException { 38 | String email = jsonObject.optString("email"); 39 | String name = jsonObject.optString("name"); 40 | String image = jsonObject.optString("image"); 41 | String id = jsonObject.optString("id"); 42 | return new UserInfoResult(name, image, email, id); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/token/RefreshAccessTokenRequest.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api.token; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | import ru.mail.auth.sdk.api.ApiCommand; 7 | import ru.mail.auth.sdk.api.ApiMethod; 8 | import ru.mail.auth.sdk.api.ApiQuery; 9 | import ru.mail.auth.sdk.api.BaseAuthResponseProcessor; 10 | import ru.mail.auth.sdk.api.ResponseProcessor; 11 | 12 | /** 13 | * Performs OAuth 2.0 Access token refresh request. 14 | */ 15 | 16 | public class RefreshAccessTokenRequest extends ApiCommand { 17 | private String mClientId; 18 | private OAuthTokensStorage mTokensStorage; 19 | 20 | public RefreshAccessTokenRequest(String clientId, OAuthTokensStorage tokensStorage) { 21 | mClientId = clientId; 22 | mTokensStorage = tokensStorage; 23 | } 24 | 25 | @Override 26 | protected ApiQuery getQuery() { 27 | return new ApiQuery.Builder() 28 | .withHost(ApiCommand.O2_API_HOST) 29 | .withMethodName(ApiMethod.TOKEN.getValue()) 30 | .withPostParam("grant_type", GrantType.REFRESH_TOKEN.getValue()) 31 | .withPostParam("client_id", mClientId) 32 | .withPostParam("refresh_token", mTokensStorage.getRefreshToken()) 33 | .build(); 34 | } 35 | 36 | @Override 37 | protected ResponseProcessor getResponseProcessor() { 38 | return new Processor(); 39 | } 40 | 41 | private class Processor extends BaseAuthResponseProcessor { 42 | @Override 43 | protected OAuthTokensResult processOkResult(JSONObject jsonObject) throws JSONException { 44 | String accessToken = jsonObject.getString("access_token"); 45 | return new OAuthTokensResult(accessToken, mTokensStorage.getRefreshToken()); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/call/CallException.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.call; 2 | 3 | import ru.mail.auth.sdk.api.CommonErrorCodes; 4 | import ru.mail.auth.sdk.api.OAuthRequestErrorCodes; 5 | 6 | public class CallException extends Exception { 7 | 8 | private final int mErrorCode; 9 | private final String mErrorMsg; 10 | private CallException mOriginalException; 11 | 12 | public CallException(int errorCode) { 13 | this(errorCode, OAuthRequestErrorCodes.toReadableString(errorCode)); 14 | } 15 | 16 | public CallException(int errorCode, String errorMsg) { 17 | super(errorMsg); 18 | mErrorCode = errorCode; 19 | mErrorMsg = errorMsg; 20 | } 21 | 22 | public int getErrorCode() { 23 | return mErrorCode; 24 | } 25 | 26 | public String getErrorMsg() { 27 | return mErrorMsg; 28 | } 29 | 30 | public static CallException retryLimitExceeded(CallException original) { 31 | CallException exception = new CallException(CommonErrorCodes.RETRY_LIMIT_EXCEEDED, "retry limit exceeded"); 32 | exception.setOriginalException(original); 33 | return exception; 34 | } 35 | 36 | public boolean isInvalidCredentialsError() { 37 | return mErrorCode == OAuthRequestErrorCodes.INVALID_CREDENTIALS; 38 | } 39 | 40 | public boolean isRecoverableAuthError() { 41 | return mErrorCode == OAuthRequestErrorCodes.INVALID_TOKEN; 42 | } 43 | 44 | public boolean isNetworkError() { 45 | return mErrorCode == CommonErrorCodes.NETWORK_ERROR; 46 | } 47 | 48 | public boolean isInternalServerError() { 49 | return mErrorCode == CommonErrorCodes.SERVER_API_ERROR; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return String.format("Code: %s, Msg: %s", mErrorCode, mErrorMsg); 55 | } 56 | 57 | public CallException getOriginalException() { 58 | return mOriginalException; 59 | } 60 | 61 | public void setOriginalException(CallException originalException) { 62 | mOriginalException = originalException; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/api/token/AccessTokenRequest.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.api.token; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | import androidx.annotation.Nullable; 7 | import ru.mail.auth.sdk.OAuthParams; 8 | import ru.mail.auth.sdk.api.ApiCommand; 9 | import ru.mail.auth.sdk.api.ApiQuery; 10 | import ru.mail.auth.sdk.api.BaseAuthResponseProcessor; 11 | import ru.mail.auth.sdk.api.ResponseProcessor; 12 | 13 | /** 14 | * Performs OAuth 2.0 tokens exchange using authorization code flow. 15 | * See https://tools.ietf.org/html/rfc6749 for more details. 16 | */ 17 | 18 | public class AccessTokenRequest extends ApiCommand { 19 | 20 | private final ApiQuery mApiQuery; 21 | 22 | public AccessTokenRequest(OAuthParams oAuthParams, 23 | String authCode, 24 | @Nullable String codeVerifier) { 25 | mApiQuery = new ApiQuery.Builder() 26 | .withHost(ApiCommand.O2_API_HOST) 27 | .withMethodName("token") 28 | .withPostParam("grant_type", GrantType.AUTH_CODE.getValue()) 29 | .withPostParam("client_id", oAuthParams.getClientId()) 30 | .withPostParam("redirect_uri", oAuthParams.getRedirectUrl()) 31 | .withPostParam("code", authCode) 32 | .withPostParam("code_verifier", codeVerifier) 33 | .build(); 34 | } 35 | 36 | @Override 37 | protected ApiQuery getQuery() { 38 | return mApiQuery; 39 | } 40 | 41 | @Override 42 | protected ResponseProcessor getResponseProcessor() { 43 | return new Processor(); 44 | } 45 | 46 | private class Processor extends BaseAuthResponseProcessor { 47 | @Override 48 | protected OAuthTokensResult processOkResult(JSONObject jsonObject) throws JSONException { 49 | String accessToken = jsonObject.getString("access_token"); 50 | String refreshToken = jsonObject.getString("refresh_token"); 51 | return new OAuthTokensResult(accessToken, refreshToken); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/call/BaseRetryMethodCall.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk.call; 2 | 3 | import android.util.Log; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import ru.mail.auth.sdk.MailRuAuthSdk; 8 | 9 | abstract class BaseRetryMethodCall extends CallDecorator { 10 | 11 | private int mTryCount = 0; 12 | private final int mMaxTryCnt; 13 | 14 | public BaseRetryMethodCall(MethodCall decorated, int retryCnt) { 15 | super(decorated); 16 | mMaxTryCnt = retryCnt; 17 | } 18 | 19 | @Override 20 | public R execute() throws CallException { 21 | CallException latestException = null; 22 | while (canRetry()) { 23 | try { 24 | delayBeforeRetry(); 25 | return super.execute(); 26 | } catch (CallException e) { 27 | latestException = e; 28 | Log.d(MailRuAuthSdk.AUTHSDK_TAG, getNameForLog() + 29 | " is trying to handle exception: " + e.toString()); 30 | if (handleException(e)) { 31 | Log.d(MailRuAuthSdk.AUTHSDK_TAG, getNameForLog() + 32 | " handled exception: " + e.toString()); 33 | incrementTryCount(); 34 | } else { 35 | throw e; 36 | } 37 | } 38 | } 39 | throw CallException.retryLimitExceeded(latestException); 40 | } 41 | 42 | private void delayBeforeRetry() { 43 | if (shouldDelayBeforeRetry() && mTryCount > 0) { 44 | try { 45 | Thread.sleep(mTryCount * TimeUnit.SECONDS.toMillis(1)); 46 | } catch (InterruptedException e) { 47 | /* ignore */ 48 | } 49 | } 50 | } 51 | 52 | protected abstract boolean shouldDelayBeforeRetry(); 53 | 54 | protected abstract String getNameForLog(); 55 | 56 | protected abstract boolean handleException(CallException e) throws CallException; 57 | 58 | private void incrementTryCount() { 59 | mTryCount++; 60 | } 61 | 62 | private boolean canRetry() { 63 | return mTryCount <= mMaxTryCnt; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /sdk/src/main/java/ru/mail/auth/sdk/MRExecutors.java: -------------------------------------------------------------------------------- 1 | package ru.mail.auth.sdk; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | 6 | import java.util.concurrent.Executor; 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.LinkedBlockingQueue; 9 | import java.util.concurrent.ThreadPoolExecutor; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | import androidx.annotation.NonNull; 13 | 14 | public class MRExecutors { 15 | 16 | private final Executor mNetworkIO; 17 | 18 | private final Executor mMainThread; 19 | 20 | private final Executor mIPC; 21 | 22 | private final Executor mSingleThreadExecutor; 23 | 24 | private static final MRExecutors sAppExecutors = new MRExecutors(); 25 | 26 | private MRExecutors(Executor networkIO, 27 | Executor ipc, 28 | Executor mainThread, 29 | Executor singleThreadExecutor) { 30 | mNetworkIO = networkIO; 31 | mIPC = ipc; 32 | mMainThread = mainThread; 33 | mSingleThreadExecutor = singleThreadExecutor; 34 | } 35 | 36 | private MRExecutors() { 37 | this(Executors.newCachedThreadPool(), 38 | Executors.newCachedThreadPool(), 39 | new MainThreadExecutor(), 40 | Executors.newSingleThreadExecutor()); 41 | } 42 | 43 | private static MRExecutors getInstance() { 44 | return sAppExecutors; 45 | } 46 | 47 | public static Executor networkIO() { 48 | return getInstance().mNetworkIO; 49 | } 50 | 51 | public static Executor mainThread() { 52 | return getInstance().mMainThread; 53 | } 54 | 55 | public static Executor singleThread() { 56 | return getInstance().mSingleThreadExecutor; 57 | } 58 | 59 | public static Executor IPC() { 60 | return getInstance().mIPC; 61 | } 62 | 63 | private static class MainThreadExecutor implements Executor { 64 | private Handler mainThreadHandler = new Handler(Looper.getMainLooper()); 65 | 66 | @Override 67 | public void execute(@NonNull Runnable command) { 68 | mainThreadHandler.post(command); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 24 | 25 | 33 | 34 | 43 | 44 | 45 | 46 | 49 | 50 |