diff --git a/.travis.yml b/.travis.yml index 98aa759..8897580 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,8 @@ env: android: components: - tools - - build-tools-23.0.3 + - build-tools-25.0.3 + - android-25 - android-24 - android-22 - android-23 @@ -29,4 +30,4 @@ before_script: - android-wait-for-emulator - adb shell input keyevent 82 & -script: ./gradlew library:connectedAndroidTest \ No newline at end of file +script: ./gradlew library:test \ No newline at end of file diff --git a/build.gradle b/build.gradle index 9405f3f..5966013 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.2.3' + classpath 'com.android.tools.build:gradle:2.3.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aebe976..2778cb3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Mar 30 11:28:56 CEST 2017 +#Tue Oct 24 09:19:37 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/library/build.gradle b/library/build.gradle index 324ee43..53c4b54 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,54 +1,18 @@ -apply plugin: 'com.android.library' apply plugin: 'me.tatarka.retrolambda' -apply plugin: 'groovyx.grooid.groovy-android' -apply plugin: 'com.github.dcendents.android-maven' +apply plugin: 'groovy' buildscript { repositories { mavenCentral() - jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.3' - classpath 'me.tatarka:gradle-retrolambda:2.5.0' - classpath 'org.codehaus.groovy:gradle-groovy-android-plugin:0.3.6' - classpath 'com.github.dcendents:android-maven-plugin:1.2' + classpath 'me.tatarka:gradle-retrolambda:3.6.1' } } group = 'com.github.rheinfabrik' -android { - compileSdkVersion 24 - buildToolsVersion "23.0.3" - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - packagingOptions { - exclude 'LICENSE' - exclude 'LICENSE.txt' - exclude 'META-INF/services/org.codehaus.groovy.transform.ASTTransformation' - } - - defaultConfig { - minSdkVersion 9 - targetSdkVersion 23 - versionCode 107 - versionName "1.0.8" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled false - } - } -} - repositories { mavenCentral() jcenter() @@ -60,15 +24,13 @@ dependencies { compile 'io.reactivex:rxjava:1.1.1' // GSON - compile 'com.google.code.gson:gson:2.4' + compile 'com.google.code.gson:gson:2.8.0' - // Spock - androidTestCompile 'org.codehaus.groovy:groovy:2.4.2:grooid' - androidTestCompile "com.andrewreitz:spock-android:1.2.1" - androidTestCompile 'com.android.support.test:testing-support-lib:0.1' - androidTestCompile('org.spockframework:spock-core:1.0-groovy-2.4') { - exclude group: 'org.codehaus.groovy' + // Testing + testCompile 'junit:junit:4.12' + testCompile('org.spockframework:spock-core:1.0-groovy-2.4') { exclude group: 'junit' } - androidTestCompile "com.google.dexmaker:dexmaker:1.2" + testCompile "cglib:cglib:2.2" + testCompile "org.objenesis:objenesis:1.2" } \ No newline at end of file diff --git a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/extras/SharedPreferencesOAuth2AccessTokenStorageSpecs.groovy b/library/src/androidTest/groovy/de/rheinfabrik/heimdall/extras/SharedPreferencesOAuth2AccessTokenStorageSpecs.groovy deleted file mode 100644 index 7690f06..0000000 --- a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/extras/SharedPreferencesOAuth2AccessTokenStorageSpecs.groovy +++ /dev/null @@ -1,136 +0,0 @@ -package de.rheinfabrik.heimdall.extras - -import android.content.SharedPreferences -import com.andrewreitz.spock.android.AndroidSpecification -import com.google.gson.Gson -import de.rheinfabrik.heimdall.OAuth2AccessToken -import spock.lang.Title; - -@Title("Tests for removeAccessToken() method in the SharedPreferencesOAuth2AccessTokenStorage class") -class SharedPreferencesOAuth2AccessTokenStorageRemoveAccessTokenSpecs extends AndroidSpecification { - - // Scenarios - - @SuppressWarnings("GroovyAssignabilityCheck") - def "it should remove the access token from the preferences"() { - - given: "A fake editor" - SharedPreferences.Editor editor = Mock(SharedPreferences.Editor) - - and: "A fake preferences with that editor" - SharedPreferences preferences = Mock(SharedPreferences) - preferences.edit() >> editor - - and: "A SharedPreferencesOAuth2AccessTokenStorage with that preferences" - SharedPreferencesOAuth2AccessTokenStorage storage = new SharedPreferencesOAuth2AccessTokenStorage<>(preferences, OAuth2AccessToken.class) - - when: "I remove the access token" - storage.removeAccessToken() - - then: "Remove is called on the editor" - 1 * editor.remove("OAuth2AccessToken") >> editor - - and: "Apply is called on the editor" - 1 * editor.apply() >> {} - } -} - -@Title("Tests for getStoredAccessToken() method in the SharedPreferencesOAuth2AccessTokenStorage class") -class SharedPreferencesOAuth2AccessTokenStorageGetStoredAccessTokenSpecs extends AndroidSpecification { - - // Scenarios - - def "it should load the stored access token"() { - - given: "Some JSON" - String json = "{\"access_token\":\"2YotnFZFEjr1zCsicMWpAA\"}" - - and: "A fake preferences returning that string" - SharedPreferences preferences = Mock(SharedPreferences) - preferences.getString("OAuth2AccessToken", _) >> json - - and: "A SharedPreferencesOAuth2AccessTokenStorage with that preferences" - SharedPreferencesOAuth2AccessTokenStorage storage = new SharedPreferencesOAuth2AccessTokenStorage<>(preferences, OAuth2AccessToken.class) - - when: "I ask for the access token" - OAuth2AccessToken token = storage.getStoredAccessToken().toBlocking().value() - - then: "The token should have the correct access token" - token.accessToken == "2YotnFZFEjr1zCsicMWpAA" - } -} - -@Title("Tests for storeAccessToken() method in the SharedPreferencesOAuth2AccessTokenStorage class") -class SharedPreferencesOAuth2AccessTokenStorageStoreAccessTokenSpecs extends AndroidSpecification { - - // Scenarios - - @SuppressWarnings("GroovyAssignabilityCheck") - def "it should store the access token in the preferences"() { - - given: "Some JSON" - String json = "{\"access_token\":\"2YotnFZFEjr1zCsicMWpAA\",\"expires_in\":0}" - - and: "An OAuth2AccessToken based on that JSON" - OAuth2AccessToken accessToken = new Gson().fromJson(json, OAuth2AccessToken.class); - - and: "A fake editor" - SharedPreferences.Editor editor = Mock(SharedPreferences.Editor) - - and: "A fake preferences with that editor" - SharedPreferences preferences = Mock(SharedPreferences) - preferences.edit() >> editor - - and: "A SharedPreferencesOAuth2AccessTokenStorage with that preferences" - SharedPreferencesOAuth2AccessTokenStorage storage = new SharedPreferencesOAuth2AccessTokenStorage<>(preferences, OAuth2AccessToken.class) - - when: "I store the access token" - storage.storeAccessToken(accessToken) - - then: "The editor is asked to save the token" - 1 * editor.putString("OAuth2AccessToken", json) >> editor - - and: "Apply is called on the editor" - 1 * editor.apply() >> {} - } -} - -@Title("Tests for hasAccessToken() method in the SharedPreferencesOAuth2AccessTokenStorage class") -class SharedPreferencesOAuth2AccessTokenStorageHasAccessTokenSpecs extends AndroidSpecification { - - // Scenarios - - @SuppressWarnings("GroovyPointlessBoolean") - def "it should emit true if there is an access token"() { - - given: "A fake preferences saying there is a token" - SharedPreferences preferences = Mock(SharedPreferences) - preferences.contains("OAuth2AccessToken") >> true - - and: "A SharedPreferencesOAuth2AccessTokenStorage with that preferences" - SharedPreferencesOAuth2AccessTokenStorage storage = new SharedPreferencesOAuth2AccessTokenStorage<>(preferences, OAuth2AccessToken.class) - - when: "I ask if there is a token" - boolean hasToken = storage.hasAccessToken().toBlocking().value() - - then: "It should be true" - hasToken == true - } - - @SuppressWarnings("GroovyPointlessBoolean") - def "it should emit false if there is NO access token"() { - - given: "A fake preferences saying there is NO token" - SharedPreferences preferences = Mock(SharedPreferences) - preferences.contains("OAuth2AccessToken") >> false - - and: "A SharedPreferencesOAuth2AccessTokenStorage with that preferences" - SharedPreferencesOAuth2AccessTokenStorage storage = new SharedPreferencesOAuth2AccessTokenStorage<>(preferences, OAuth2AccessToken.class) - - when: "I ask if there is a token" - boolean hasToken = storage.hasAccessToken().toBlocking().value() - - then: "It should be false" - hasToken == false - } -} diff --git a/library/src/main/java/de/rheinfabrik/heimdall/grants/OAuth2AuthorizationCodeGrant.java b/library/src/main/java/de/rheinfabrik/heimdall/grants/OAuth2AuthorizationCodeGrant.java index b2a1d1c..a7b38b9 100644 --- a/library/src/main/java/de/rheinfabrik/heimdall/grants/OAuth2AuthorizationCodeGrant.java +++ b/library/src/main/java/de/rheinfabrik/heimdall/grants/OAuth2AuthorizationCodeGrant.java @@ -1,6 +1,12 @@ package de.rheinfabrik.heimdall.grants; -import android.net.Uri; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; import de.rheinfabrik.heimdall.OAuth2AccessToken; import rx.Observable; @@ -64,21 +70,21 @@ public abstract class OAuth2AuthorizationCodeGrant authorizationUri() { - return mAuthorizationUriSubject.asObservable(); + public final Observable authorizationUri() { + return mAuthorizationUrlSubject.asObservable(); } /** * Command you should send a value to whenever an url in e.g. your web view has been loaded. */ - public final PublishSubject onUriLoadedCommand = PublishSubject.create(); + public final PublishSubject onUrlLoadedCommand = PublishSubject.create(); // Abstract Api /** - * Called when the grant needs the authorization uri. + * Called when the grant needs the authorization url. */ - public abstract Uri buildAuthorizationUri(); + public abstract URL buildAuthorizationUrl(); /** * Called when the grant was able to grab the code and it wants to exchange it for an access token. @@ -87,20 +93,48 @@ public final Observable authorizationUri() { // Members - private final BehaviorSubject mAuthorizationUriSubject = BehaviorSubject.create(); + private final BehaviorSubject mAuthorizationUrlSubject = BehaviorSubject.create(); // OAuth2AccessToken @Override public Single grantNewAccessToken() { - mAuthorizationUriSubject.onNext(buildAuthorizationUri()); + mAuthorizationUrlSubject.onNext(buildAuthorizationUrl()); - return onUriLoadedCommand - .map(uri -> uri.getQueryParameter(RESPONSE_TYPE)) + return onUrlLoadedCommand + .map(uri -> { + List values = getQueryParameters(uri).get(RESPONSE_TYPE); + if (values != null && values.size() >= 1) { + return values.get(0); + } + + return null; + }) .filter(code -> code != null) .take(1) .retry() .concatMap(this::exchangeTokenUsingCode) .toSingle(); } + + // Private + + private static Map> getQueryParameters(URL url) { + final Map> query_pairs = new LinkedHashMap<>(); + final String[] pairs = url.getQuery().split("&"); + for (String pair : pairs) { + final int idx = pair.indexOf("="); + + try { + final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), "UTF-8") : pair; + if (!query_pairs.containsKey(key)) { + query_pairs.put(key, new LinkedList<>()); + } + final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : null; + query_pairs.get(key).add(value); + } catch (Exception ignored) {} + } + + return query_pairs; + } } diff --git a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/OAuth2AccessTokenManagerSpecs.groovy b/library/src/test/groovy/de/rheinfabrik/heimdall/OAuth2AccessTokenManagerSpecs.groovy similarity index 95% rename from library/src/androidTest/groovy/de/rheinfabrik/heimdall/OAuth2AccessTokenManagerSpecs.groovy rename to library/src/test/groovy/de/rheinfabrik/heimdall/OAuth2AccessTokenManagerSpecs.groovy index 40fb13f..43111c1 100644 --- a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/OAuth2AccessTokenManagerSpecs.groovy +++ b/library/src/test/groovy/de/rheinfabrik/heimdall/OAuth2AccessTokenManagerSpecs.groovy @@ -1,13 +1,13 @@ package de.rheinfabrik.heimdall -import com.andrewreitz.spock.android.AndroidSpecification import de.rheinfabrik.heimdall.grants.OAuth2Grant import de.rheinfabrik.heimdall.grants.OAuth2RefreshAccessTokenGrant import rx.Single +import spock.lang.Specification import spock.lang.Title @Title("Tests for the constructor of the OAuth2AccessTokenManager class") -class OAuth2AccessTokenManagerConstructorSpecs extends AndroidSpecification { +class OAuth2AccessTokenManagerConstructorSpecs extends Specification { // Scenarios @@ -26,7 +26,7 @@ class OAuth2AccessTokenManagerConstructorSpecs extends AndroidSpecification { } @Title("Tests for the grantNewAccessToken() function of the OAuth2AccessTokenManager class") -class OAuth2AccessTokenManagerGrantNewAccessTokenSpecs extends AndroidSpecification { +class OAuth2AccessTokenManagerGrantNewAccessTokenSpecs extends Specification { // Scenarios @@ -112,7 +112,7 @@ class OAuth2AccessTokenManagerGrantNewAccessTokenSpecs extends AndroidSpecificat } @Title("Tests for the getStorage() function of the OAuth2AccessTokenManager class") -class OAuth2AccessTokenManagerGetStorageSpecs extends AndroidSpecification { +class OAuth2AccessTokenManagerGetStorageSpecs extends Specification { // Scenarios @@ -133,7 +133,7 @@ class OAuth2AccessTokenManagerGetStorageSpecs extends AndroidSpecification { } @Title("Tests for the getValidAccessToken() function of the OAuth2AccessTokenManager class") -class OAuth2AccessTokenManagerGetValidAccessTokenSpecs extends AndroidSpecification { +class OAuth2AccessTokenManagerGetValidAccessTokenSpecs extends Specification { // Scenarios diff --git a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/OAuth2AccessTokenSpecs.groovy b/library/src/test/groovy/de/rheinfabrik/heimdall/OAuth2AccessTokenSpecs.groovy similarity index 79% rename from library/src/androidTest/groovy/de/rheinfabrik/heimdall/OAuth2AccessTokenSpecs.groovy rename to library/src/test/groovy/de/rheinfabrik/heimdall/OAuth2AccessTokenSpecs.groovy index f3684aa..952ef01 100644 --- a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/OAuth2AccessTokenSpecs.groovy +++ b/library/src/test/groovy/de/rheinfabrik/heimdall/OAuth2AccessTokenSpecs.groovy @@ -1,11 +1,11 @@ package de.rheinfabrik.heimdall -import com.andrewreitz.spock.android.AndroidSpecification import com.google.gson.Gson +import spock.lang.Specification import spock.lang.Title @Title("Specs for serialization in the OAuth2AccessToken class.") -class OAuth2AccessTokenSerializationSpecs extends AndroidSpecification { +class OAuth2AccessTokenSerializationSpecs extends Specification { // Setup @@ -29,7 +29,7 @@ class OAuth2AccessTokenSerializationSpecs extends AndroidSpecification { String json = new Gson().toJson(accessToken) then: "The JSON should be as expected" - json == "{\"access_token\":\"at\",\"heimdall_expiration_date\":{\"year\":1970,\"month\":0,\"dayOfMonth\":1,\"hourOfDay\":0,\"minute\":0,\"second\":0},\"expires_in\":3600,\"refresh_token\":\"rt\",\"token_type\":\"bearer\"}" + json == "{\"token_type\":\"bearer\",\"access_token\":\"at\",\"refresh_token\":\"rt\",\"expires_in\":3600,\"heimdall_expiration_date\":{\"year\":1970,\"month\":0,\"dayOfMonth\":1,\"hourOfDay\":0,\"minute\":0,\"second\":0}}" } def "It should create the correct OAuth2AccessToken for a given JSON"() { @@ -41,21 +41,19 @@ class OAuth2AccessTokenSerializationSpecs extends AndroidSpecification { OAuth2AccessToken accessToken = new Gson().fromJson(json, OAuth2AccessToken.class) then: "The OAuth2AccessToken should be as expected" - with(accessToken, { - accessToken.refreshToken == "rt" - accessToken.expiresIn == 3600 - accessToken.accessToken == "at" - accessToken.tokenType == "bearer" - - Calendar calendar = Calendar.getInstance() - calendar.setTimeInMillis(0) - accessToken.expirationDate.timeInMillis == calendar.timeInMillis - }) + accessToken.refreshToken == "rt" + accessToken.expiresIn == 3600 + accessToken.accessToken == "at" + accessToken.tokenType == "bearer" + + Calendar calendar = Calendar.getInstance() + calendar.setTimeInMillis(0) + accessToken.expirationDate.timeInMillis == calendar.timeInMillis } } @Title("Specs for the isExpired() function in the OAuth2AccessToken class.") -class OAuth2AccessTokenIsExpiredSpecs extends AndroidSpecification { +class OAuth2AccessTokenIsExpiredSpecs extends Specification { // Scenarios diff --git a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2AuthorizationCodeGrantSpecs.groovy b/library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2AuthorizationCodeGrantSpecs.groovy similarity index 83% rename from library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2AuthorizationCodeGrantSpecs.groovy rename to library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2AuthorizationCodeGrantSpecs.groovy index 1511216..b9cfdd1 100644 --- a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2AuthorizationCodeGrantSpecs.groovy +++ b/library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2AuthorizationCodeGrantSpecs.groovy @@ -1,10 +1,10 @@ package de.rheinfabrik.heimdall.grants -import com.andrewreitz.spock.android.AndroidSpecification +import spock.lang.Specification import spock.lang.Title @Title("Specs for the OAuth2AuthorizationCodeGrant") -class OAuth2AuthorizationCodeGrantSpecs extends AndroidSpecification { +class OAuth2AuthorizationCodeGrantSpecs extends Specification { // Scenarios diff --git a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2ClientCredentialsGrantSpecs.groovy b/library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2ClientCredentialsGrantSpecs.groovy similarity index 75% rename from library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2ClientCredentialsGrantSpecs.groovy rename to library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2ClientCredentialsGrantSpecs.groovy index 5f22fdd..82ff1a8 100644 --- a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2ClientCredentialsGrantSpecs.groovy +++ b/library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2ClientCredentialsGrantSpecs.groovy @@ -1,10 +1,10 @@ package de.rheinfabrik.heimdall.grants -import com.andrewreitz.spock.android.AndroidSpecification +import spock.lang.Specification import spock.lang.Title @Title("Specs for the OAuth2ClientCredentialsGrant") -class OAuth2ClientCredentialsGrantSpecs extends AndroidSpecification { +class OAuth2ClientCredentialsGrantSpecs extends Specification { // Scenarios diff --git a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2ImplicitGrantSpecs.groovy b/library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2ImplicitGrantSpecs.groovy similarity index 75% rename from library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2ImplicitGrantSpecs.groovy rename to library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2ImplicitGrantSpecs.groovy index 483385f..1949fd3 100644 --- a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2ImplicitGrantSpecs.groovy +++ b/library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2ImplicitGrantSpecs.groovy @@ -1,10 +1,10 @@ package de.rheinfabrik.heimdall.grants -import com.andrewreitz.spock.android.AndroidSpecification +import spock.lang.Specification import spock.lang.Title @Title("Specs for the OAuth2ImplicitGrant") -class OAuth2ImplicitGrantSpecs extends AndroidSpecification { +class OAuth2ImplicitGrantSpecs extends Specification { // Scenarios diff --git a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2RefreshAccessTokenGrantSpecs.groovy b/library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2RefreshAccessTokenGrantSpecs.groovy similarity index 74% rename from library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2RefreshAccessTokenGrantSpecs.groovy rename to library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2RefreshAccessTokenGrantSpecs.groovy index d0fd61c..0a45c4a 100644 --- a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2RefreshAccessTokenGrantSpecs.groovy +++ b/library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2RefreshAccessTokenGrantSpecs.groovy @@ -1,10 +1,10 @@ package de.rheinfabrik.heimdall.grants -import com.andrewreitz.spock.android.AndroidSpecification +import spock.lang.Specification import spock.lang.Title @Title("Specs for the OAuth2RefreshAccessTokenGrant") -class OAuth2RefreshAccessTokenGrantSpecs extends AndroidSpecification { +class OAuth2RefreshAccessTokenGrantSpecs extends Specification { // Scenarios diff --git a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2ResourceOwnerPasswordCredentialsGrantSpecs.groovy b/library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2ResourceOwnerPasswordCredentialsGrantSpecs.groovy similarity index 73% rename from library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2ResourceOwnerPasswordCredentialsGrantSpecs.groovy rename to library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2ResourceOwnerPasswordCredentialsGrantSpecs.groovy index b7197ab..ee77302 100644 --- a/library/src/androidTest/groovy/de/rheinfabrik/heimdall/grants/OAuth2ResourceOwnerPasswordCredentialsGrantSpecs.groovy +++ b/library/src/test/groovy/de/rheinfabrik/heimdall/grants/OAuth2ResourceOwnerPasswordCredentialsGrantSpecs.groovy @@ -1,10 +1,10 @@ package de.rheinfabrik.heimdall.grants -import com.andrewreitz.spock.android.AndroidSpecification +import spock.lang.Specification import spock.lang.Title @Title("Specs for the OAuth2ResourceOwnerPasswordCredentialsGrant") -class OAuth2ResourceOwnerPasswordCredentialsGrantSpecs extends AndroidSpecification { +class OAuth2ResourceOwnerPasswordCredentialsGrantSpecs extends Specification { // Scenarios diff --git a/library/src/test/java/de/rheinfabrik/heimdall/EmptyTestClass.java b/library/src/test/java/de/rheinfabrik/heimdall/EmptyTestClass.java new file mode 100644 index 0000000..961a39f --- /dev/null +++ b/library/src/test/java/de/rheinfabrik/heimdall/EmptyTestClass.java @@ -0,0 +1,7 @@ +package de.rheinfabrik.heimdall; + +public class EmptyTestClass { + // This is an empty class. It exists only because the gradle compileTestGroovy + // build step for some reason does not properly compile the Groovy tests if there is + // not at least one class in the Java test directory +} diff --git a/sample/build.gradle b/sample/build.gradle index 6bbc5a4..bb539d7 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -7,18 +7,18 @@ buildscript { } dependencies { - classpath 'me.tatarka:gradle-retrolambda:2.5.0' + classpath 'me.tatarka:gradle-retrolambda:3.6.1' } } android { - compileSdkVersion 24 - buildToolsVersion "23.0.3" + compileSdkVersion 25 + buildToolsVersion "25.0.3" defaultConfig { applicationId "de.rheinfabrik.heimdall" minSdkVersion 15 - targetSdkVersion 24 + targetSdkVersion 25 versionCode 1 versionName "1.0" } diff --git a/sample/src/main/java/de/rheinfabrik/heimdalldroid/TraktTvAPIConfiguration.java b/sample/src/main/java/de/rheinfabrik/heimdalldroid/TraktTvAPIConfiguration.java new file mode 100644 index 0000000..45e4eb2 --- /dev/null +++ b/sample/src/main/java/de/rheinfabrik/heimdalldroid/TraktTvAPIConfiguration.java @@ -0,0 +1,7 @@ +package de.rheinfabrik.heimdalldroid; + +public class TraktTvAPIConfiguration { + public static final String CLIENT_ID = "***REMOVED***"; + public static final String CLIENT_SECRET = "***REMOVED***"; + public static final String REDIRECT_URI = "***REMOVED***"; +} diff --git a/sample/src/main/java/de/rheinfabrik/heimdalldroid/actvities/LoginActivity.java b/sample/src/main/java/de/rheinfabrik/heimdalldroid/actvities/LoginActivity.java index 93971d4..a27c06e 100644 --- a/sample/src/main/java/de/rheinfabrik/heimdalldroid/actvities/LoginActivity.java +++ b/sample/src/main/java/de/rheinfabrik/heimdalldroid/actvities/LoginActivity.java @@ -9,6 +9,9 @@ import com.trello.rxlifecycle.components.support.RxAppCompatActivity; +import java.net.MalformedURLException; +import java.net.URL; + import butterknife.ButterKnife; import butterknife.InjectView; import de.rheinfabrik.heimdalldroid.R; @@ -57,7 +60,7 @@ private void authorize() { // Listen for the authorization url and load it once needed grant.authorizationUri() - .map(Uri::toString) + .map(URL::toString) .compose(bindToLifecycle()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(mWebView::loadUrl); @@ -66,14 +69,20 @@ private void authorize() { mWebView.setWebViewClient(new WebViewClient() { @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - super.onPageStarted(view, url, favicon); + public void onPageStarted(WebView view, String urlString, Bitmap favicon) { + super.onPageStarted(view, urlString, favicon); + + try { + URL url = new URL(urlString); + grant.onUrlLoadedCommand.onNext(url); - grant.onUriLoadedCommand.onNext(Uri.parse(url)); + // Hide redirect page from user + if (urlString.startsWith(grant.redirectUri)) { + mWebView.setVisibility(View.GONE); + } + } catch (MalformedURLException ignored) { + // Empty - // Hide redirect page from user - if (url.startsWith(grant.redirectUri)) { - mWebView.setVisibility(View.GONE); } } }); diff --git a/sample/src/main/java/de/rheinfabrik/heimdalldroid/network/TraktTvApiFactory.java b/sample/src/main/java/de/rheinfabrik/heimdalldroid/network/TraktTvApiFactory.java index f9c47ee..2193334 100644 --- a/sample/src/main/java/de/rheinfabrik/heimdalldroid/network/TraktTvApiFactory.java +++ b/sample/src/main/java/de/rheinfabrik/heimdalldroid/network/TraktTvApiFactory.java @@ -2,6 +2,7 @@ import com.google.gson.Gson; +import de.rheinfabrik.heimdalldroid.TraktTvAPIConfiguration; import retrofit.RestAdapter; import retrofit.converter.GsonConverter; diff --git a/sample/src/main/java/de/rheinfabrik/heimdalldroid/network/oauth2/TraktTvAuthorizationCodeGrant.java b/sample/src/main/java/de/rheinfabrik/heimdalldroid/network/oauth2/TraktTvAuthorizationCodeGrant.java index 4b7a953..7e9fd3d 100644 --- a/sample/src/main/java/de/rheinfabrik/heimdalldroid/network/oauth2/TraktTvAuthorizationCodeGrant.java +++ b/sample/src/main/java/de/rheinfabrik/heimdalldroid/network/oauth2/TraktTvAuthorizationCodeGrant.java @@ -2,6 +2,8 @@ import android.net.Uri; +import java.net.URL; + import de.rheinfabrik.heimdall.OAuth2AccessToken; import de.rheinfabrik.heimdall.grants.OAuth2AuthorizationCodeGrant; import de.rheinfabrik.heimdalldroid.network.TraktTvApiFactory; @@ -20,12 +22,20 @@ public class TraktTvAuthorizationCodeGrant extends OAuth2AuthorizationCodeGrant< // OAuth2AuthorizationCodeGrant @Override - public Uri buildAuthorizationUri() { - return Uri.parse("https://trakt.tv/oauth/authorize") - .buildUpon() - .appendQueryParameter("client_id", clientId) - .appendQueryParameter("redirect_uri", redirectUri) - .appendQueryParameter("response_type", RESPONSE_TYPE).build(); + public URL buildAuthorizationUrl() { + try { + return new URL( + Uri.parse("https://trakt.tv/oauth/authorize") + .buildUpon() + .appendQueryParameter("client_id", clientId) + .appendQueryParameter("redirect_uri", redirectUri) + .appendQueryParameter("response_type", RESPONSE_TYPE) + .build() + .toString() + ); + } catch (Exception ignored) { + return null; + } } @Override diff --git a/sample/src/main/java/de/rheinfabrik/heimdalldroid/network/oauth2/TraktTvOauth2AccessTokenManager.java b/sample/src/main/java/de/rheinfabrik/heimdalldroid/network/oauth2/TraktTvOauth2AccessTokenManager.java index bb4a2b3..e479ad4 100644 --- a/sample/src/main/java/de/rheinfabrik/heimdalldroid/network/oauth2/TraktTvOauth2AccessTokenManager.java +++ b/sample/src/main/java/de/rheinfabrik/heimdalldroid/network/oauth2/TraktTvOauth2AccessTokenManager.java @@ -6,10 +6,10 @@ import de.rheinfabrik.heimdall.OAuth2AccessToken; import de.rheinfabrik.heimdall.OAuth2AccessTokenManager; import de.rheinfabrik.heimdall.OAuth2AccessTokenStorage; -import de.rheinfabrik.heimdall.extras.SharedPreferencesOAuth2AccessTokenStorage; -import de.rheinfabrik.heimdalldroid.network.TraktTvAPIConfiguration; +import de.rheinfabrik.heimdalldroid.TraktTvAPIConfiguration; import de.rheinfabrik.heimdalldroid.network.TraktTvApiFactory; import de.rheinfabrik.heimdalldroid.network.models.RevokeAccessTokenBody; +import de.rheinfabrik.heimdalldroid.utils.SharedPreferencesOAuth2AccessTokenStorage; import rx.Single; /** diff --git a/library/src/main/java/de/rheinfabrik/heimdall/extras/SharedPreferencesOAuth2AccessTokenStorage.java b/sample/src/main/java/de/rheinfabrik/heimdalldroid/utils/SharedPreferencesOAuth2AccessTokenStorage.java old mode 100644 new mode 100755 similarity index 98% rename from library/src/main/java/de/rheinfabrik/heimdall/extras/SharedPreferencesOAuth2AccessTokenStorage.java rename to sample/src/main/java/de/rheinfabrik/heimdalldroid/utils/SharedPreferencesOAuth2AccessTokenStorage.java index 5bc9612..a5d8e19 --- a/library/src/main/java/de/rheinfabrik/heimdall/extras/SharedPreferencesOAuth2AccessTokenStorage.java +++ b/sample/src/main/java/de/rheinfabrik/heimdalldroid/utils/SharedPreferencesOAuth2AccessTokenStorage.java @@ -1,4 +1,4 @@ -package de.rheinfabrik.heimdall.extras; +package de.rheinfabrik.heimdalldroid.utils; import android.content.SharedPreferences;