diff --git a/.editorconfig b/.editorconfig index 225962c..e7502aa 100644 --- a/.editorconfig +++ b/.editorconfig @@ -401,6 +401,7 @@ ij_groovy_wrap_long_lines = false [*.{kt,kts}] ktlint_code_style = android_studio ktlint_standard_import-ordering = disabled +ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than = 1 ij_kotlin_align_in_columns_case_branch = false ij_kotlin_align_multiline_binary_operation = false ij_kotlin_align_multiline_extends_list = false @@ -408,7 +409,7 @@ ij_kotlin_align_multiline_method_parentheses = false ij_kotlin_align_multiline_parameters = true ij_kotlin_align_multiline_parameters_in_calls = false ij_kotlin_allow_trailing_comma = true -ij_kotlin_allow_trailing_comma_on_call_site = false +ij_kotlin_allow_trailing_comma_on_call_site = true ij_kotlin_assignment_wrap = normal ij_kotlin_blank_lines_after_class_header = 0 ij_kotlin_blank_lines_around_block_when_branches = 0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c6d003..ca78b06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Piano SDK for Android +## v2.11.0 +* Increased minSdkVersion from 21 to 23 +* Android 15 compatibility +* Add access for lat pageViewId from Composer execution +* Remove code deprecated about year ago +* Updated dependencies: + - Kotlin [1.9.23 -> 1.9.24] + - org.jetbrains.kotlinx:kotlinx-coroutines-core [1.8.0 -> 1.9.0] + https://github.com/Kotlin/kotlinx.coroutines + - androidx.lifecycle:lifecycle-common-java8 [2.7.0 -> 2.8.7] + https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.7 + - androidx.credentials:credentials [1.2.2 -> 1.3.0] + https://developer.android.com/jetpack/androidx/releases/credentials#1.3.0 + - androidx.activity:activity [1.9.0 -> 1.9.3] + https://developer.android.com/jetpack/androidx/releases/activity#1.9.3 + - androidx.annotation:annotation [1.7.1 -> 1.9.1] + https://developer.android.com/jetpack/androidx/releases/annotation#1.9.1 + - androidx.appcompat:appcompat [1.6.1 -> 1.7.0] + https://developer.android.com/jetpack/androidx/releases/appcompat#1.7.0 + - androidx.fragment:fragment [1.7.0 -> 1.8.5] + https://developer.android.com/jetpack/androidx/releases/fragment#1.8.5 + - com.google.android.gms:play-services-basement [18.3.0 -> 18.5.0] + - com.google.android.libraries.identity.googleid:googleid [1.1.0 -> 1.1.1] + - com.facebook.android:facebook-login [17.0.0 -> 17.0.2] + https://github.com/facebook/facebook-android-sdk + - io.piano.android:cxense [2.6.0 -> 2.6.1] + https://docs.piano.io/product/dmp + ## v2.10.0 * Updated to Kotlin 1.9 * Deprecated `renderTemplateUrl` for show recommendations diff --git a/composer-c1x/src/main/java/io/piano/android/composer/c1x/C1xInterceptor.kt b/composer-c1x/src/main/java/io/piano/android/composer/c1x/C1xInterceptor.kt index da46d67..c7ff61f 100644 --- a/composer-c1x/src/main/java/io/piano/android/composer/c1x/C1xInterceptor.kt +++ b/composer-c1x/src/main/java/io/piano/android/composer/c1x/C1xInterceptor.kt @@ -42,7 +42,7 @@ internal class C1xInterceptor( location = request.url, contentId = request.contentId, referrer = request.referer, - customParameters = mutableListOf(CustomParameter(PARAM_USERSTATE, userState)) + customParameters = mutableListOf(CustomParameter(PARAM_USERSTATE, userState)), ).apply { if (externalUserId != null) { addExternalUserIds(externalUserId) diff --git a/composer-c1x/src/main/java/io/piano/android/composer/c1x/ShowRecommendationsController.kt b/composer-c1x/src/main/java/io/piano/android/composer/c1x/ShowRecommendationsController.kt index 2e98cb6..28bd51c 100644 --- a/composer-c1x/src/main/java/io/piano/android/composer/c1x/ShowRecommendationsController.kt +++ b/composer-c1x/src/main/java/io/piano/android/composer/c1x/ShowRecommendationsController.kt @@ -6,11 +6,12 @@ import io.piano.android.composer.model.Event import io.piano.android.composer.model.events.ShowRecommendations import io.piano.android.showhelper.BaseShowController -public class ShowRecommendationsController(event: Event) : - BaseShowController( - event.eventData, - with(event.eventData) { WidgetJs(widgetId, siteId) } - ) { +public class ShowRecommendationsController( + event: Event, +) : BaseShowController( + event.eventData, + with(event.eventData) { WidgetJs(widgetId, siteId) }, +) { private val trackingId = event.eventExecutionContext.trackingId override val url: String = URL override val fragmentTag: String = FRAGMENT_TAG diff --git a/composer-c1x/src/main/java/io/piano/android/composer/c1x/ShowRecommendationsDialogFragment.kt b/composer-c1x/src/main/java/io/piano/android/composer/c1x/ShowRecommendationsDialogFragment.kt index 6b28e60..db6b33b 100644 --- a/composer-c1x/src/main/java/io/piano/android/composer/c1x/ShowRecommendationsDialogFragment.kt +++ b/composer-c1x/src/main/java/io/piano/android/composer/c1x/ShowRecommendationsDialogFragment.kt @@ -36,7 +36,7 @@ public class ShowRecommendationsDialogFragment : BaseShowDialogFragment { override fun WebView.configure(jsInterface: BaseJsInterface?) { prepare( jsInterface as? WidgetJs ?: WidgetJs(widgetId, siteId), - this@ShowRecommendationsDialogFragment + this@ShowRecommendationsDialogFragment, ) } diff --git a/composer-show-template/src/main/java/io/piano/android/composer/showtemplate/ShowTemplateController.kt b/composer-show-template/src/main/java/io/piano/android/composer/showtemplate/ShowTemplateController.kt index a187ebb..58d5cdc 100644 --- a/composer-show-template/src/main/java/io/piano/android/composer/showtemplate/ShowTemplateController.kt +++ b/composer-show-template/src/main/java/io/piano/android/composer/showtemplate/ShowTemplateController.kt @@ -55,7 +55,7 @@ public class ShowTemplateController constructor( override fun onPause(owner: LifecycleOwner) { handler.removeCallbacksAndMessages(null) } - } + }, ) handler.postDelayed(func, value * 1000L) } else { diff --git a/composer/api/composer.api b/composer/api/composer.api index 3dc1d58..f0c178f 100644 --- a/composer/api/composer.api +++ b/composer/api/composer.api @@ -15,12 +15,12 @@ public final class io/piano/android/composer/Composer { public final fun browserIdProvider (Lkotlin/jvm/functions/Function0;)Lio/piano/android/composer/Composer; public final fun clearStoredData ()V public final fun gaClientId (Ljava/lang/String;)Lio/piano/android/composer/Composer; - public final fun getAccessToken ()Ljava/lang/String; public final fun getBrowserId ()Ljava/lang/String; public final fun getEdgeCookies ()Lio/piano/android/composer/model/EdgeCookies; public final fun getExperience (Lio/piano/android/composer/model/ExperienceRequest;Ljava/util/Collection;Lio/piano/android/composer/listeners/ExceptionListener;)V public final fun getExperience (Lio/piano/android/composer/model/ExperienceRequest;Lkotlin/jvm/functions/Function1;Lio/piano/android/composer/listeners/ExceptionListener;)V public static final fun getInstance ()Lio/piano/android/composer/Composer; + public final fun getPageViewId ()Ljava/lang/String; public final fun getPianoConsents ()Lio/piano/android/consents/PianoConsents; public static final fun init (Landroid/content/Context;Ljava/lang/String;)V public static final fun init (Landroid/content/Context;Ljava/lang/String;Lio/piano/android/composer/Composer$Endpoint;)V diff --git a/composer/src/main/java/io/piano/android/composer/AidInterceptor.kt b/composer/src/main/java/io/piano/android/composer/AidInterceptor.kt index 55b6f42..5e80f49 100644 --- a/composer/src/main/java/io/piano/android/composer/AidInterceptor.kt +++ b/composer/src/main/java/io/piano/android/composer/AidInterceptor.kt @@ -4,16 +4,16 @@ import okhttp3.Interceptor import okhttp3.Response import java.io.IOException -internal class AidInterceptor(private val aid: String) : Interceptor { +internal class AidInterceptor( + private val aid: String, +) : Interceptor { @Throws(IOException::class) - override fun intercept(chain: Interceptor.Chain): Response { - return chain.proceed( - chain.request() - .newBuilder() - .header(AID_HEADER, aid) - .build() - ) - } + override fun intercept(chain: Interceptor.Chain): Response = chain.proceed( + chain.request() + .newBuilder() + .header(AID_HEADER, aid) + .build(), + ) companion object { internal const val AID_HEADER = "piano-app-id" } diff --git a/composer/src/main/java/io/piano/android/composer/Composer.kt b/composer/src/main/java/io/piano/android/composer/Composer.kt index 875625d..ca2093f 100644 --- a/composer/src/main/java/io/piano/android/composer/Composer.kt +++ b/composer/src/main/java/io/piano/android/composer/Composer.kt @@ -1,6 +1,7 @@ package io.piano.android.composer import android.content.Context +import io.piano.android.composer.Composer.Endpoint import io.piano.android.composer.listeners.EventTypeListener import io.piano.android.composer.listeners.EventsListener import io.piano.android.composer.listeners.ExceptionListener @@ -66,15 +67,6 @@ public class Composer internal constructor( public var browserId: String? = null private set - /** - * Gets Composer's user access token for Edge CDN. - * - * @return Access token for Edge CDN. - */ - @Deprecated("Use `edgeCookies.tac`", ReplaceWith("edgeCookies.tac")) - public val accessToken: String - get() = prefsStorage.tpAccessCookie - /** * Gets all required cookies for Edge CDN * @@ -83,6 +75,12 @@ public class Composer internal constructor( public val edgeCookies: EdgeCookies get() = edgeCookiesProvider.edgeCookies + /** + * Gets pageViewId for the latest Composer execution + */ + public var pageViewId: String? = null + private set + /** * Adds an experience interceptor to the Composer. * @@ -154,14 +152,14 @@ public class Composer internal constructor( exceptionListener: ExceptionListener, ): Unit = getExperience( request, - exceptionListener + exceptionListener, ) { response -> processExperienceResponse( request, response, eventTypeListeners, null, - exceptionListener + exceptionListener, ) } @@ -183,14 +181,14 @@ public class Composer internal constructor( exceptionListener: ExceptionListener, ): Unit = getExperience( request, - exceptionListener + exceptionListener, ) { response -> processExperienceResponse( request, response, emptyList(), eventsListener, - exceptionListener + exceptionListener, ) } @@ -206,8 +204,8 @@ public class Composer internal constructor( trackingId, EVENT_TYPE_EXTERNAL_EVENT, EVENT_GROUP_CLOSE, - pianoConsents?.consents.orEmpty() - ) + pianoConsents?.consents.orEmpty(), + ), ).enqueue(emptyCallback) } @@ -224,8 +222,8 @@ public class Composer internal constructor( EVENT_TYPE_EXTERNAL_EVENT, EVENT_GROUP_INIT, pianoConsents?.consents.orEmpty(), - CX_CUSTOM_PARAMS - ) + CX_CUSTOM_PARAMS, + ), ).enqueue(emptyCallback) } @@ -244,8 +242,8 @@ public class Composer internal constructor( EVENT_TYPE_EXTERNAL_LINK, EVENT_GROUP_CLICK, pianoConsents?.consents.orEmpty(), - params - ) + params, + ), ).enqueue(emptyCallback) } @@ -265,8 +263,8 @@ public class Composer internal constructor( customFormName, trackingId, userToken, - pianoConsents?.consents.orEmpty() - ) + pianoConsents?.consents.orEmpty(), + ), ).enqueue(emptyCallback) /** @@ -285,8 +283,8 @@ public class Composer internal constructor( customFormName, trackingId, userToken, - pianoConsents?.consents.orEmpty() - ) + pianoConsents?.consents.orEmpty(), + ), ).enqueue(emptyCallback) /** @@ -301,16 +299,16 @@ public class Composer internal constructor( processResponse: (ExperienceResponse) -> Unit, ) { experienceInterceptors.forEach { it.beforeExecute(request) } - composerApi.getExperience( - httpHelper.convertExperienceRequest( - request, - aid, - browserIdProvider, - userToken, - pianoConsents?.consents.orEmpty(), - pianoConsents?.productsToPurposesMapping.orEmpty() - ) - ).enqueue( + val fields = httpHelper.convertExperienceRequest( + request, + aid, + browserIdProvider, + userToken, + pianoConsents?.consents.orEmpty(), + pianoConsents?.productsToPurposesMapping.orEmpty(), + ) + pageViewId = fields[HttpHelper.PARAM_PAGEVIEW_ID] + composerApi.getExperience(fields).enqueue( object : Callback> { override fun onResponse( call: Call>, @@ -331,7 +329,7 @@ public class Composer internal constructor( override fun onFailure(call: Call>, t: Throwable) = exceptionListener.onException(t.toComposerException()) - } + }, ) } @@ -391,7 +389,7 @@ public class Composer internal constructor( aid, userToken, gaClientId, - pianoConsents?.consents.orEmpty() + pianoConsents?.consents.orEmpty(), ).forEach { (key, value) -> builder.addQueryParameter(key, value) } @@ -400,7 +398,7 @@ public class Composer internal constructor( eventData } return copy( - eventData = data + eventData = data, ) } @@ -508,7 +506,7 @@ public class Composer internal constructor( context.applicationContext, aid, endpoint, - pianoConsents ?: runCatching { PianoConsents.getInstance() }.getOrNull() + pianoConsents ?: runCatching { PianoConsents.getInstance() }.getOrNull(), ) /** diff --git a/composer/src/main/java/io/piano/android/composer/ComposerJsonAdapterFactory.kt b/composer/src/main/java/io/piano/android/composer/ComposerJsonAdapterFactory.kt index 3f321b7..1bb54fe 100644 --- a/composer/src/main/java/io/piano/android/composer/ComposerJsonAdapterFactory.kt +++ b/composer/src/main/java/io/piano/android/composer/ComposerJsonAdapterFactory.kt @@ -14,14 +14,16 @@ internal class ComposerJsonAdapterFactory : JsonAdapter.Factory { Types.newParameterizedType( Map::class.java, String::class.java, - Types.newParameterizedType(List::class.java, String::class.java) - ) - ) + Types.newParameterizedType(List::class.java, String::class.java), + ), + ), ) + Any::class.java -> ObjectJsonAdapter( moshi.nextAdapter(this, Any::class.java, annotations), - moshi.adapter(Long::class.java) + moshi.adapter(Long::class.java), ) + else -> null } } diff --git a/composer/src/main/java/io/piano/android/composer/DependenciesProvider.kt b/composer/src/main/java/io/piano/android/composer/DependenciesProvider.kt index ad482ab..fcc4ee7 100644 --- a/composer/src/main/java/io/piano/android/composer/DependenciesProvider.kt +++ b/composer/src/main/java/io/piano/android/composer/DependenciesProvider.kt @@ -38,8 +38,8 @@ internal class DependenciesProvider private constructor( HttpLoggingInterceptor.Level.BODY } else { HttpLoggingInterceptor.Level.NONE - } - ) + }, + ), ) .build() private val moshi = Moshi.Builder() @@ -70,7 +70,7 @@ internal class DependenciesProvider private constructor( prefsStorage, pianoConsents, moshi.adapter(PprvContainer::class.java), - moshi.adapter(PcusContainer::class.java) + moshi.adapter(PcusContainer::class.java), ) internal val composer: Composer = Composer( @@ -81,7 +81,7 @@ internal class DependenciesProvider private constructor( aid, endpoint, edgeCookiesProvider, - pianoConsents + pianoConsents, ) @Suppress("NOTHING_TO_INLINE") diff --git a/composer/src/main/java/io/piano/android/composer/EdgeCookiesProvider.kt b/composer/src/main/java/io/piano/android/composer/EdgeCookiesProvider.kt index 0122349..d4fab52 100644 --- a/composer/src/main/java/io/piano/android/composer/EdgeCookiesProvider.kt +++ b/composer/src/main/java/io/piano/android/composer/EdgeCookiesProvider.kt @@ -25,7 +25,7 @@ internal class EdgeCookiesProvider( prefsStorage.xbuilderBrowserCookie, lastUserToken.orEmpty(), buildPprvValue(), - lastUserSegmentsContainer?.let { pcusAdapter.toJson(PcusContainer(it)) }?.toBase64String().orEmpty() + lastUserSegmentsContainer?.let { pcusAdapter.toJson(PcusContainer(it)) }?.toBase64String().orEmpty(), ) internal fun userSegments(userSegmentsContainer: UserSegmentsContainer?) { @@ -44,8 +44,8 @@ internal class EdgeCookiesProvider( it.id to ConsentModeWrapper(c.mode) } }.toMap(), - it.productsToPurposesMapping.mapKeys { it.key.id } - ) + it.productsToPurposesMapping.mapKeys { it.key.id }, + ), ) }?.toBase64String().orEmpty() diff --git a/composer/src/main/java/io/piano/android/composer/EventJsonAdapterFactory.kt b/composer/src/main/java/io/piano/android/composer/EventJsonAdapterFactory.kt index f6bf87e..6c440fd 100644 --- a/composer/src/main/java/io/piano/android/composer/EventJsonAdapterFactory.kt +++ b/composer/src/main/java/io/piano/android/composer/EventJsonAdapterFactory.kt @@ -39,12 +39,14 @@ internal class EventJsonAdapterFactory : JsonAdapter.Factory { moshi.adapter(ShowRecommendations::class.java), moshi.adapter(ShowTemplate::class.java), StubAdapter { UserSegment(true) }, - StubAdapter { UserSegment(false) } - ) + StubAdapter { UserSegment(false) }, + ), ).nullSafe() } - private class StubAdapter(private val stubFunction: () -> T) : JsonAdapter() { + private class StubAdapter( + private val stubFunction: () -> T, + ) : JsonAdapter() { override fun fromJson(reader: JsonReader): T = stubFunction().also { reader.skipValue() } override fun toJson(writer: JsonWriter, value: T?) { TODO("Not supported") @@ -68,7 +70,7 @@ internal class EventJsonAdapterFactory : JsonAdapter.Factory { private val options = JsonReader.Options.of( EVENT_MODULE_PARAMS, EVENT_EXECUTION_CONTEXT, - EVENT_PARAMS + EVENT_PARAMS, ) private val eventTypeKeyOptions = JsonReader.Options.of(EVENT_TYPE) private val eventSubtypesOptions = JsonReader.Options.of( @@ -82,7 +84,7 @@ internal class EventJsonAdapterFactory : JsonAdapter.Factory { EVENT_TYPE_SHOW_RECOMMENDATIONS, EVENT_TYPE_SHOW_TEMPLATE, EVENT_TYPE_USER_SEGMENT_TRUE, - EVENT_TYPE_USER_SEGMENT_FALSE + EVENT_TYPE_USER_SEGMENT_FALSE, ) override fun fromJson(reader: JsonReader): Event<*>? { @@ -102,22 +104,25 @@ internal class EventJsonAdapterFactory : JsonAdapter.Factory { ?: throw Util.unexpectedNull( EVENT_MODULE_PARAMS, EVENT_MODULE_PARAMS, - this + this, ) + 1 -> eventExecutionContext = eventExecutionContextAdapter.fromJson(this) ?: throw Util.unexpectedNull( EVENT_EXECUTION_CONTEXT, EVENT_EXECUTION_CONTEXT, - this + this, ) + 2 -> eventData = eventDataAdapters[eventType].fromJson(this) ?: throw Util.unexpectedNull( EVENT_PARAMS, EVENT_PARAMS, - this + this, ) + -1 -> { skipName() skipValue() @@ -129,18 +134,18 @@ internal class EventJsonAdapterFactory : JsonAdapter.Factory { eventModuleParams ?: throw Util.missingProperty( EVENT_MODULE_PARAMS, EVENT_MODULE_PARAMS, - this + this, ), eventExecutionContext ?: throw Util.missingProperty( EVENT_EXECUTION_CONTEXT, EVENT_EXECUTION_CONTEXT, - this + this, ), eventData ?: throw Util.missingProperty( EVENT_PARAMS, EVENT_PARAMS, - this - ) + this, + ), ) } } @@ -154,7 +159,7 @@ internal class EventJsonAdapterFactory : JsonAdapter.Factory { continue } return selectString(eventSubtypesOptions).takeIf { it != -1 } ?: throw JsonDataException( - "Unknown event type '${nextString()}', expected one of $eventSubtypesOptions" + "Unknown event type '${nextString()}', expected one of $eventSubtypesOptions", ) } throw JsonDataException("Can't find key $EVENT_TYPE in json") diff --git a/composer/src/main/java/io/piano/android/composer/HttpHelper.kt b/composer/src/main/java/io/piano/android/composer/HttpHelper.kt index 0086053..dc03ade 100644 --- a/composer/src/main/java/io/piano/android/composer/HttpHelper.kt +++ b/composer/src/main/java/io/piano/android/composer/HttpHelper.kt @@ -30,8 +30,8 @@ internal class HttpHelper( Types.newParameterizedType( Map::class.java, String::class.java, - String::class.java - ) + String::class.java, + ), ) } @@ -42,9 +42,9 @@ internal class HttpHelper( String::class.java, Types.newParameterizedType( List::class.java, - String::class.java - ) - ) + String::class.java, + ), + ), ) } @@ -52,8 +52,8 @@ internal class HttpHelper( moshi.adapter>( Types.newParameterizedType( List::class.java, - ActiveMeter::class.java - ) + ActiveMeter::class.java, + ), ) } @@ -66,8 +66,8 @@ internal class HttpHelper( Types.newParameterizedType( Map::class.java, Int::class.javaObjectType, - Int::class.javaObjectType - ) + Int::class.javaObjectType, + ), ) } @@ -76,8 +76,8 @@ internal class HttpHelper( Types.newParameterizedType( Map::class.java, Int::class.javaObjectType, - Purpose::class.java - ) + Purpose::class.java, + ), ) } @@ -86,8 +86,8 @@ internal class HttpHelper( Types.newParameterizedType( Map::class.java, Purpose::class.java, - Consent::class.java - ) + Consent::class.java, + ), ) } @@ -147,7 +147,7 @@ internal class HttpHelper( .orEmpty(), PARAM_CONSENT_PURPOSES to productsToPurposesMapping.mapKeys { it.key.id }.takeUnless { it.isEmpty() } ?.let { consentPurposesAdapter.toJson(it) } - .orEmpty() + .orEmpty(), ).filterNotEmptyValues() }.toMap() @@ -172,7 +172,7 @@ internal class HttpHelper( PARAM_EVENT_CUSTOM_PARAMS to customParameters.takeUnless { it.isEmpty() } ?.let { mapAdapter.toJson(it) }.orEmpty(), PARAM_EVENT_COOKIE_CONSENTS to consents.takeUnless { it.isEmpty() } - ?.let { vxConsentAdapter.toJson(it) }.orEmpty() + ?.let { vxConsentAdapter.toJson(it) }.orEmpty(), ) internal fun buildCustomFormTracking( @@ -188,7 +188,7 @@ internal class HttpHelper( PARAM_EVENT_TRACKING_ID to trackingId, PARAM_CUSTOM_FORM_NAME to customFormName, PARAM_EVENT_COOKIE_CONSENTS to consents.takeUnless { it.isEmpty() } - ?.let { vxConsentAdapter.toJson(it) }.orEmpty() + ?.let { vxConsentAdapter.toJson(it) }.orEmpty(), ).filterNotEmptyValues().toMap() internal fun buildShowTemplateParameters( @@ -218,7 +218,7 @@ internal class HttpHelper( PARAM_ACTIVE_METERS to eventExecutionContext.activeMeters.takeUnless { it.isNullOrEmpty() } ?.let { activeMetersAdapter.toJson(it) }.orEmpty(), PARAM_EVENT_COOKIE_CONSENTS to consents.takeUnless { it.isEmpty() } - ?.let { vxConsentAdapter.toJson(it) }.orEmpty() + ?.let { vxConsentAdapter.toJson(it) }.orEmpty(), ).filterNotEmptyValues() }.toMap() @@ -228,7 +228,7 @@ internal class HttpHelper( PARAM_ZONE to zone.orEmpty(), PARAM_TAGS to tags.takeUnless { it.isEmpty() } ?.joinToString(separator = ",") - .orEmpty() + .orEmpty(), ).filterNotEmptyValues() @Suppress("NOTHING_TO_INLINE") diff --git a/composer/src/main/java/io/piano/android/composer/KotlinExtensions.kt b/composer/src/main/java/io/piano/android/composer/KotlinExtensions.kt index 15636a0..f4526d8 100644 --- a/composer/src/main/java/io/piano/android/composer/KotlinExtensions.kt +++ b/composer/src/main/java/io/piano/android/composer/KotlinExtensions.kt @@ -21,7 +21,7 @@ public suspend fun Composer.getExperience( ): List> = suspendCancellableCoroutine { continuation -> getExperience( request, - { events: List> -> continuation.resume(events) } + { events: List> -> continuation.resume(events) }, ) { continuation.resumeWithException(it) } diff --git a/composer/src/main/java/io/piano/android/composer/ObjectJsonAdapter.kt b/composer/src/main/java/io/piano/android/composer/ObjectJsonAdapter.kt index d987167..0c02eb8 100644 --- a/composer/src/main/java/io/piano/android/composer/ObjectJsonAdapter.kt +++ b/composer/src/main/java/io/piano/android/composer/ObjectJsonAdapter.kt @@ -8,18 +8,16 @@ internal class ObjectJsonAdapter( private val delegate: JsonAdapter, private val longAdapter: JsonAdapter, ) : JsonAdapter() { - override fun fromJson(reader: JsonReader): Any? { - return if (reader.peek() == JsonReader.Token.NUMBER) { - runCatching { - longAdapter.fromJson(reader.peekJson()).also { - reader.skipValue() - } - }.recover { - delegate.fromJson(reader) - }.getOrNull() - } else { + override fun fromJson(reader: JsonReader): Any? = if (reader.peek() == JsonReader.Token.NUMBER) { + runCatching { + longAdapter.fromJson(reader.peekJson()).also { + reader.skipValue() + } + }.recover { delegate.fromJson(reader) - } + }.getOrNull() + } else { + delegate.fromJson(reader) } override fun toJson(writer: JsonWriter, value: Any?) = delegate.toJson(writer, value) diff --git a/composer/src/main/java/io/piano/android/composer/PrefsStorage.kt b/composer/src/main/java/io/piano/android/composer/PrefsStorage.kt index 5f49e12..29799b4 100644 --- a/composer/src/main/java/io/piano/android/composer/PrefsStorage.kt +++ b/composer/src/main/java/io/piano/android/composer/PrefsStorage.kt @@ -7,16 +7,16 @@ import java.util.Date import java.util.concurrent.TimeUnit @RestrictTo(RestrictTo.Scope.LIBRARY) -internal class PrefsStorage(context: Context) { +internal class PrefsStorage( + context: Context, +) { private val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) internal fun clear() { prefs.edit().clear().apply() } - internal fun getValueForKey(key: String): String? { - return prefs.getString(key, null) - } + internal fun getValueForKey(key: String): String? = prefs.getString(key, null) internal fun setValueForKey(key: String, value: String?) { prefs.edit().putString(key, value).apply() @@ -66,7 +66,7 @@ internal class PrefsStorage(context: Context) { var visitTimeout: Long get() = prefs.getLong( KEY_VISIT_TIMEOUT, - VISIT_TIMEOUT_FALLBACK + VISIT_TIMEOUT_FALLBACK, ) set(milliseconds) { prefs.edit().putLong(KEY_VISIT_TIMEOUT, milliseconds).apply() diff --git a/composer/src/main/java/io/piano/android/composer/RequestPolicyInterceptor.kt b/composer/src/main/java/io/piano/android/composer/RequestPolicyInterceptor.kt index 48e6e26..b5e7519 100644 --- a/composer/src/main/java/io/piano/android/composer/RequestPolicyInterceptor.kt +++ b/composer/src/main/java/io/piano/android/composer/RequestPolicyInterceptor.kt @@ -5,7 +5,9 @@ import okhttp3.Response import java.util.Date import java.util.concurrent.TimeUnit -internal class RequestPolicyInterceptor(private val prefsStorage: PrefsStorage) : Interceptor { +internal class RequestPolicyInterceptor( + private val prefsStorage: PrefsStorage, +) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val currentPolicyTime = prefsStorage.requestPolicyTime if (currentPolicyTime > System.currentTimeMillis()) { diff --git a/composer/src/main/java/io/piano/android/composer/UserAgentInterceptor.kt b/composer/src/main/java/io/piano/android/composer/UserAgentInterceptor.kt index 2fb7a66..93b3859 100644 --- a/composer/src/main/java/io/piano/android/composer/UserAgentInterceptor.kt +++ b/composer/src/main/java/io/piano/android/composer/UserAgentInterceptor.kt @@ -4,14 +4,14 @@ import okhttp3.Interceptor import okhttp3.Response import java.io.IOException -internal class UserAgentInterceptor(private val userAgent: String) : Interceptor { +internal class UserAgentInterceptor( + private val userAgent: String, +) : Interceptor { @Throws(IOException::class) - override fun intercept(chain: Interceptor.Chain): Response { - return chain.proceed( - chain.request() - .newBuilder() - .header("User-Agent", userAgent) - .build() - ) - } + override fun intercept(chain: Interceptor.Chain): Response = chain.proceed( + chain.request() + .newBuilder() + .header("User-Agent", userAgent) + .build(), + ) } diff --git a/composer/src/main/java/io/piano/android/composer/listeners/EventTypeListener.kt b/composer/src/main/java/io/piano/android/composer/listeners/EventTypeListener.kt index 0935ef0..c1e5dac 100644 --- a/composer/src/main/java/io/piano/android/composer/listeners/EventTypeListener.kt +++ b/composer/src/main/java/io/piano/android/composer/listeners/EventTypeListener.kt @@ -33,9 +33,7 @@ public interface EventTypeListener { * @param event event * @return True, if this listener can process this type of events, otherwise False. Default answer is False. */ - public fun canProcess(event: Event): Boolean { - return false - } + public fun canProcess(event: Event): Boolean = false } /** diff --git a/composer/src/main/java/io/piano/android/composer/model/DisplayMode.kt b/composer/src/main/java/io/piano/android/composer/model/DisplayMode.kt index 00207bd..d4cffce 100644 --- a/composer/src/main/java/io/piano/android/composer/model/DisplayMode.kt +++ b/composer/src/main/java/io/piano/android/composer/model/DisplayMode.kt @@ -4,7 +4,9 @@ import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = false) -public enum class DisplayMode(public val mode: String) { +public enum class DisplayMode( + public val mode: String, +) { @Json(name = "modal") MODAL("modal"), @@ -12,7 +14,5 @@ public enum class DisplayMode(public val mode: String) { INLINE("inline"), ; - override fun toString(): String { - return mode - } + override fun toString(): String = mode } diff --git a/composer/src/main/java/io/piano/android/composer/model/EdgeCookies.kt b/composer/src/main/java/io/piano/android/composer/model/EdgeCookies.kt index bc32b65..86b5da2 100644 --- a/composer/src/main/java/io/piano/android/composer/model/EdgeCookies.kt +++ b/composer/src/main/java/io/piano/android/composer/model/EdgeCookies.kt @@ -31,13 +31,15 @@ public class EdgeCookies( "xbc" to xbc, "__utp" to userToken, "_pprv" to pprv, - "_pcus" to pcus - ).filterValues { it.isNotEmpty() } + "_pcus" to pcus, + ).filterValues { it.isNotEmpty() }, ) } @JsonClass(generateAdapter = true) -internal class ConsentModeWrapper(val mode: ConsentMode) +internal class ConsentModeWrapper( + val mode: ConsentMode, +) @JsonClass(generateAdapter = true) internal class PprvContainer( @@ -46,4 +48,6 @@ internal class PprvContainer( ) @JsonClass(generateAdapter = true) -internal class PcusContainer(val userSegments: UserSegmentsContainer) +internal class PcusContainer( + val userSegments: UserSegmentsContainer, +) diff --git a/composer/src/main/java/io/piano/android/composer/model/ExperienceRequest.kt b/composer/src/main/java/io/piano/android/composer/model/ExperienceRequest.kt index 3c5403c..fa3c863 100644 --- a/composer/src/main/java/io/piano/android/composer/model/ExperienceRequest.kt +++ b/composer/src/main/java/io/piano/android/composer/model/ExperienceRequest.kt @@ -267,27 +267,25 @@ public class ExperienceRequest private constructor( * @return ExperienceRequest instance */ @Suppress("unused") // Public API. - public fun build(): ExperienceRequest { - return ExperienceRequest( - debug, - Collections.unmodifiableMap(customVariables), - url, - referer, - Collections.unmodifiableList(tags), - Collections.unmodifiableList(keywords), - zone, - title, - description, - contentId, - contentType, - contentCreated, - contentAuthor, - contentSection, - contentIsNative, - customParameters, - edgeResult - ) - } + public fun build(): ExperienceRequest = ExperienceRequest( + debug, + Collections.unmodifiableMap(customVariables), + url, + referer, + Collections.unmodifiableList(tags), + Collections.unmodifiableList(keywords), + zone, + title, + description, + contentId, + contentType, + contentCreated, + contentAuthor, + contentSection, + contentIsNative, + customParameters, + edgeResult, + ) } public companion object { diff --git a/composer/src/main/java/io/piano/android/composer/model/events/EventType.kt b/composer/src/main/java/io/piano/android/composer/model/events/EventType.kt index 7cd23bd..69f4a94 100644 --- a/composer/src/main/java/io/piano/android/composer/model/events/EventType.kt +++ b/composer/src/main/java/io/piano/android/composer/model/events/EventType.kt @@ -99,7 +99,8 @@ public data class ShowForm( override val containerSelector: String, override val displayMode: DisplayMode, override val showCloseButton: Boolean, -) : EventType(), BaseShowType +) : EventType(), + BaseShowType /** * Represents an event type to show a login prompt. @@ -131,7 +132,8 @@ public data class ShowRecommendations( override val showCloseButton: Boolean, val siteId: String, val type: String, -) : EventType(), BaseShowType +) : EventType(), + BaseShowType /** * Represents an event type to show a template. @@ -153,7 +155,8 @@ public data class ShowTemplate( val delayBy: DelayBy, override val showCloseButton: Boolean, val url: String? = null, -) : EventType(), BaseShowType +) : EventType(), + BaseShowType /** * Represents an event type for user segmentation. diff --git a/composer/src/test/java/io/piano/android/composer/AidInterceptorTest.kt b/composer/src/test/java/io/piano/android/composer/AidInterceptorTest.kt index a9c5721..7ab81e1 100644 --- a/composer/src/test/java/io/piano/android/composer/AidInterceptorTest.kt +++ b/composer/src/test/java/io/piano/android/composer/AidInterceptorTest.kt @@ -34,7 +34,7 @@ class AidInterceptorTest { .newCall( Request.Builder() .url(mockWebServer.url("/")) - .build() + .build(), ).execute() assertEquals(AID_VALUE, mockWebServer.takeRequest().getHeader(AidInterceptor.AID_HEADER)) } diff --git a/composer/src/test/java/io/piano/android/composer/ComposerTest.kt b/composer/src/test/java/io/piano/android/composer/ComposerTest.kt index 5562e4c..6ec9033 100644 --- a/composer/src/test/java/io/piano/android/composer/ComposerTest.kt +++ b/composer/src/test/java/io/piano/android/composer/ComposerTest.kt @@ -55,10 +55,10 @@ class ComposerTest { any(), anyOrNull(), anyOrNull(), - any() + any(), ) } doReturn mapOf( - DUMMY_STRING to DUMMY_STRING2 + DUMMY_STRING to DUMMY_STRING2, ) } private val edgeCookiesProvider: EdgeCookiesProvider = mock { @@ -68,7 +68,7 @@ class ComposerTest { DUMMY_STRING, DUMMY_STRING2, DUMMY_STRING, - DUMMY_STRING2 + DUMMY_STRING2, ) } private val pianoConsents: PianoConsents = mock { @@ -83,14 +83,14 @@ class ComposerTest { DUMMY_AID, Composer.Endpoint.SANDBOX, edgeCookiesProvider, - pianoConsents - ) + pianoConsents, + ), ) private val experienceRequest: ExperienceRequest = mock() private val resultListeners = listOf( mock(), - mock() + mock(), ) private val exceptionListener: ExceptionListener = mock() @@ -123,16 +123,11 @@ class ComposerTest { "", Composer.Endpoint.SANDBOX, edgeCookiesProvider, - pianoConsents + pianoConsents, ) } } - @Test - fun accessToken() { - assertEquals(DUMMY_STRING, composer.accessToken) - } - @Test fun getExperienceResponseException() = getExperienceWithCallbackCheck { val response = Response.success>(null) @@ -148,9 +143,9 @@ class ComposerTest { mock(), listOf( mock(), - mock() - ) - ) + mock(), + ), + ), ) it.onResponse(experienceCall, response) verifyExceptionListenerArgument(null) @@ -161,7 +156,7 @@ class ComposerTest { fun getExperienceResponseSuccess() = getExperienceWithCallbackCheck { val experienceResponse: ExperienceResponse = mock() val response = Response.success( - Data(experienceResponse, emptyList()) + Data(experienceResponse, emptyList()), ) it.onResponse(experienceCall, response) verify(composer).processExperienceResponse( @@ -169,7 +164,7 @@ class ComposerTest { experienceResponse, resultListeners, null, - exceptionListener + exceptionListener, ) verify(exceptionListener, never()).onException(any()) } @@ -187,7 +182,7 @@ class ComposerTest { val eventTypes = listOf( ShowTemplate("", "", mock(), null, mock(), true), mock(), - mock() + mock(), ) val response = ExperienceResponse( null, @@ -201,8 +196,8 @@ class ComposerTest { EventsContainer( eventTypes.map { Event(mock(), mock(), it) - } - ) + }, + ), ) val iterations = eventTypes.size @@ -220,7 +215,7 @@ class ComposerTest { val listeners = listOf( showTemplateListener, experienceExecuteListener, - userSegmentListener + userSegmentListener, ) composer.processExperienceResponse( @@ -228,7 +223,7 @@ class ComposerTest { response, listeners, null, - exceptionListener + exceptionListener, ) verify(httpHelper).afterExecute(experienceRequest, response) verify(showTemplateListener, times(iterations)).canProcess(any()) @@ -251,14 +246,14 @@ class ComposerTest { null, null, null, - EventsContainer(listOf(Event(mock(), mock(), mock()))) + EventsContainer(listOf(Event(mock(), mock(), mock()))), ) composer.processExperienceResponse( experienceRequest, experienceResponse, listOf(), null, - exceptionListener + exceptionListener, ) verify(httpHelper).afterExecute(experienceRequest, experienceResponse) verify(exceptionListener, never()).onException(any()) @@ -275,14 +270,14 @@ class ComposerTest { null, null, null, - EventsContainer(emptyList()) + EventsContainer(emptyList()), ) composer.processExperienceResponse( experienceRequest, response, resultListeners, null, - exceptionListener + exceptionListener, ) verify(httpHelper).afterExecute(experienceRequest, response) for (listener in resultListeners) { @@ -302,7 +297,7 @@ class ComposerTest { DUMMY_STRING, Composer.EVENT_TYPE_EXTERNAL_EVENT, Composer.EVENT_GROUP_CLOSE, - emptyMap() + emptyMap(), ) composer.trackRecommendationsDisplay(DUMMY_STRING) verify(httpHelper).buildEventTracking( @@ -310,7 +305,7 @@ class ComposerTest { Composer.EVENT_TYPE_EXTERNAL_EVENT, Composer.EVENT_GROUP_INIT, emptyMap(), - Composer.CX_CUSTOM_PARAMS + Composer.CX_CUSTOM_PARAMS, ) composer.trackRecommendationsClick(DUMMY_STRING) verify(httpHelper).buildEventTracking( @@ -318,7 +313,7 @@ class ComposerTest { Composer.EVENT_TYPE_EXTERNAL_LINK, Composer.EVENT_GROUP_CLICK, emptyMap(), - Composer.CX_CUSTOM_PARAMS + Composer.CX_CUSTOM_PARAMS, ) verify(generalApi, times(3)).trackExternalEvent(any()) verify(call, times(3)).enqueue(any()) diff --git a/composer/src/test/java/io/piano/android/composer/ExecuteMobileResponseTest.kt b/composer/src/test/java/io/piano/android/composer/ExecuteMobileResponseTest.kt index 7ae879e..63d2fcc 100644 --- a/composer/src/test/java/io/piano/android/composer/ExecuteMobileResponseTest.kt +++ b/composer/src/test/java/io/piano/android/composer/ExecuteMobileResponseTest.kt @@ -20,8 +20,8 @@ class ExecuteMobileResponseTest { val adapter = moshi.adapter>( Types.newParameterizedType( Data::class.java, - ExperienceResponse::class.java - ) + ExperienceResponse::class.java, + ), ) val response = adapter.fromJson(RAW_JSON) assertNotNull(response) diff --git a/composer/src/test/java/io/piano/android/composer/HttpHelperTest.kt b/composer/src/test/java/io/piano/android/composer/HttpHelperTest.kt index ba43903..74be351 100644 --- a/composer/src/test/java/io/piano/android/composer/HttpHelperTest.kt +++ b/composer/src/test/java/io/piano/android/composer/HttpHelperTest.kt @@ -58,8 +58,8 @@ class HttpHelperTest { experienceIdsProvider, prefsStorage, moshi, - DUMMY_STRING - ) + DUMMY_STRING, + ), ) @Test @@ -70,7 +70,7 @@ class HttpHelperTest { { null }, null, emptyMap(), - emptyMap() + emptyMap(), ) requestMap.apply { assertEquals(17, size) @@ -95,7 +95,7 @@ class HttpHelperTest { null, null, null, - EventsContainer(emptyList()) + EventsContainer(emptyList()), ) httpHelper.afterExecute(mock(), experienceResponse) verify(prefsStorage).xbuilderBrowserCookie = DUMMY_STRING @@ -126,16 +126,16 @@ class HttpHelperTest { DUMMY_STRING, DUMMY_STRING2, mapOf( - Purpose.CONTENT_PERSONALISATION to Consent(ConsentMode.OPT_OUT, listOf(Product.COMPOSER)) - ) - ) + Purpose.CONTENT_PERSONALISATION to Consent(ConsentMode.OPT_OUT, listOf(Product.COMPOSER)), + ), + ), ) { assertEquals(6, size) assertEquals(DUMMY_STRING, this[HttpHelper.PARAM_EVENT_TRACKING_ID]) assertEquals(DUMMY_STRING2, this[HttpHelper.PARAM_USER_TOKEN]) assertEquals( """{"CP":{"mode":"opt-out","products":["COMPOSER"]}}""", - this[HttpHelper.PARAM_EVENT_COOKIE_CONSENTS] + this[HttpHelper.PARAM_EVENT_COOKIE_CONSENTS], ) verify(experienceIdsProvider).getPageViewId(any()) } @@ -157,7 +157,7 @@ class HttpHelperTest { DUMMY_STRING2, UserSegmentsContainer(null, null), null, - meters + meters, ), ShowTemplate( DUMMY_STRING2, @@ -166,11 +166,11 @@ class HttpHelperTest { DUMMY_STRING, DelayBy( DelayBy.DelayType.TIME, - 0 + 0, ), false, - null - ) + null, + ), ) with( httpHelper.buildShowTemplateParameters( @@ -180,9 +180,9 @@ class HttpHelperTest { null, null, mapOf( - Purpose.CONTENT_PERSONALISATION to Consent(ConsentMode.OPT_OUT, listOf(Product.COMPOSER)) - ) - ) + Purpose.CONTENT_PERSONALISATION to Consent(ConsentMode.OPT_OUT, listOf(Product.COMPOSER)), + ), + ), ) { assertEquals(12, size) assertEquals(DUMMY_STRING, this[HttpHelper.PARAM_AID]) diff --git a/composer/src/test/java/io/piano/android/composer/PrefsStorageTest.kt b/composer/src/test/java/io/piano/android/composer/PrefsStorageTest.kt index 5162831..65ffca1 100644 --- a/composer/src/test/java/io/piano/android/composer/PrefsStorageTest.kt +++ b/composer/src/test/java/io/piano/android/composer/PrefsStorageTest.kt @@ -143,7 +143,7 @@ class PrefsStorageTest { @Test fun getVisitTimeout() { whenever(prefs.getLong(PrefsStorage.KEY_VISIT_TIMEOUT, PrefsStorage.VISIT_TIMEOUT_FALLBACK)).thenReturn( - DUMMY_LONG + DUMMY_LONG, ) assertEquals(DUMMY_LONG, prefsStorage.visitTimeout) verify(prefs).getLong(PrefsStorage.KEY_VISIT_TIMEOUT, PrefsStorage.VISIT_TIMEOUT_FALLBACK) diff --git a/composer/src/test/java/io/piano/android/composer/UserAgentInterceptorTest.kt b/composer/src/test/java/io/piano/android/composer/UserAgentInterceptorTest.kt index 0dfb521..219096a 100644 --- a/composer/src/test/java/io/piano/android/composer/UserAgentInterceptorTest.kt +++ b/composer/src/test/java/io/piano/android/composer/UserAgentInterceptorTest.kt @@ -18,7 +18,7 @@ class UserAgentInterceptorTest : BaseInterceptorTest() { .newCall( Request.Builder() .url(mockWebServer.url("/")) - .build() + .build(), ).execute() assertEquals(USER_AGENT_VALUE, mockWebServer.takeRequest().getHeader("User-Agent")) } diff --git a/gradle.properties b/gradle.properties index 0a9caa6..cca4764 100755 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -VERSION_NAME=2.10.0 +VERSION_NAME=2.11.0 GROUP=io.piano.android POM_DESCRIPTION=Piano SDK for Android diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 049254e..76af6e1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,42 +1,42 @@ [versions] # Plugins -kotlin = "1.9.23" -android = "8.4.0" +kotlin = "1.9.24" +android = "8.6.1" dokka = "1.9.20" -binaryCompatibility = "0.14.0" +binaryCompatibility = "0.16.3" versionUpdater = "0.51.0" -ktlint = "12.1.0" -mavenRelease = "0.28.0" -moshiIR = "0.25.1" -ksp = "1.9.23-1.0.20" +ktlint = "12.1.2" +mavenRelease = "0.30.0" +moshiIR = "0.26.0" +ksp = "1.9.24-1.0.20" # AndroidX libraries -compatLibrary = "1.6.1" -androidxCredentials = "1.2.2" -androidxActivity = "1.9.0" -annotationsLibrary = "1.7.1" -fragmentLibrary = "1.7.0" -materialLibrary = "1.11.0" -lifecycleLibrary = "2.7.0" +compatLibrary = "1.7.0" +androidxCredentials = "1.3.0" +androidxActivity = "1.9.3" +annotationsLibrary = "1.9.1" +fragmentLibrary = "1.8.5" +materialLibrary = "1.12.0" +lifecycleLibrary = "2.8.7" prefsLibrary = "1.2.1" multidex = "2.0.1" # Third party Libraries -facebookLogin = "17.0.0" -googleId = "1.1.0" -googlePlayServicesBase = "18.3.0" +facebookLogin = "17.0.2" +googleId = "1.1.1" +googlePlayServicesBase = "18.5.0" retrofit = "2.11.0" okhttp = "4.12.0" moshi = "1.15.1" timber = "5.0.1" pianoConsents = "1.0.0" -cxense = "2.6.0" -coroutines = "1.8.0" +cxense = "2.6.1" +coroutines = "1.9.0" # Test Libraries junit = "4.13.2" -androidxTestCore = "1.5.0" -androidxTestExtJunit = "1.1.5" +androidxTestCore = "1.6.1" +androidxTestExtJunit = "1.2.1" mockitoKotlin = "2.2.0" mockitoCore = "3.12.1" diff --git a/gradle/plugins/src/main/kotlin/io/piano/android/configuration/AndroidConfig.kt b/gradle/plugins/src/main/kotlin/io/piano/android/configuration/AndroidConfig.kt index 52a6811..f4410c6 100644 --- a/gradle/plugins/src/main/kotlin/io/piano/android/configuration/AndroidConfig.kt +++ b/gradle/plugins/src/main/kotlin/io/piano/android/configuration/AndroidConfig.kt @@ -3,10 +3,10 @@ package io.piano.android.configuration import org.gradle.api.JavaVersion internal object AndroidConfig { - const val androidBuildTools = "34.0.0" - const val androidMinSdk = 21 - const val androidTargetSdk = 34 - const val androidCompileSdk = 34 + const val androidBuildTools = "35.0.0" + const val androidMinSdk = 23 + const val androidTargetSdk = 35 + const val androidCompileSdk = 35 val compileSourceVersion = JavaVersion.VERSION_1_8 val compileTargetVersion = JavaVersion.VERSION_1_8 } diff --git a/gradle/plugins/src/main/kotlin/io/piano/android/ktlint/KtlintConfigPlugin.kt b/gradle/plugins/src/main/kotlin/io/piano/android/ktlint/KtlintConfigPlugin.kt index 9da608d..5ee1e06 100644 --- a/gradle/plugins/src/main/kotlin/io/piano/android/ktlint/KtlintConfigPlugin.kt +++ b/gradle/plugins/src/main/kotlin/io/piano/android/ktlint/KtlintConfigPlugin.kt @@ -11,7 +11,7 @@ class KtlintConfigPlugin : Plugin { apply() if (this != rootProject) { extensions.configure(KtlintExtension::class.java) { - version.set("1.2.1") + version.set("1.4.1") android.set(true) } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 12a4ce9..b1750fb 100755 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip diff --git a/id/id-oauth-google/src/main/java/io/piano/android/id/google/GoogleOAuthProvider.kt b/id/id-oauth-google/src/main/java/io/piano/android/id/google/GoogleOAuthProvider.kt index 7b948bc..690bda2 100644 --- a/id/id-oauth-google/src/main/java/io/piano/android/id/google/GoogleOAuthProvider.kt +++ b/id/id-oauth-google/src/main/java/io/piano/android/id/google/GoogleOAuthProvider.kt @@ -28,7 +28,7 @@ public class GoogleOAuthProvider : PianoIdOAuthProvider { return OAuthSuccessResult( name, - GoogleIdTokenCredential.createFrom(credential.data).idToken + GoogleIdTokenCredential.createFrom(credential.data).idToken, ) } catch (e: GetCredentialCancellationException) { return OAuthCancelledResult diff --git a/id/id/api/id.api b/id/id/api/id.api index fae177c..959c8b5 100644 --- a/id/id/api/id.api +++ b/id/id/api/id.api @@ -25,25 +25,15 @@ public final class io/piano/android/id/PianoId { public static final field WIDGET_REGISTER Ljava/lang/String; public fun ()V public static final fun getInstance ()Lio/piano/android/id/PianoIdClient; - public static final fun getUserInfo (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V - public static final fun getUserInfo (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V public static final fun init (Ljava/lang/String;Ljava/lang/String;Lio/piano/android/consents/PianoConsents;)Lio/piano/android/id/PianoIdClient; public static final fun init (Lokhttp3/HttpUrl;Ljava/lang/String;Lio/piano/android/consents/PianoConsents;)Lio/piano/android/id/PianoIdClient; public static final fun isPianoIdUri (Landroid/net/Uri;)Z public static final fun parsePianoIdToken (Landroid/net/Uri;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun parsePianoIdToken (Landroid/net/Uri;Lkotlin/jvm/functions/Function1;)V - public static final fun putUserInfo (Ljava/lang/String;Lio/piano/android/id/models/PianoUserInfo;Lkotlin/jvm/functions/Function1;)V - public static final fun refreshToken (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V - public static final fun signIn ()Lio/piano/android/id/PianoIdClient$SignInContext; - public static final fun signOut (Ljava/lang/String;)V - public static final fun signOut (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V } public final class io/piano/android/id/PianoId$Companion { public final fun getInstance ()Lio/piano/android/id/PianoIdClient; - public final fun getUserInfo (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V - public final fun getUserInfo (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V - public static synthetic fun getUserInfo$default (Lio/piano/android/id/PianoId$Companion;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V public final fun init (Ljava/lang/String;Ljava/lang/String;Lio/piano/android/consents/PianoConsents;)Lio/piano/android/id/PianoIdClient; public final fun init (Lokhttp3/HttpUrl;Ljava/lang/String;Lio/piano/android/consents/PianoConsents;)Lio/piano/android/id/PianoIdClient; public static synthetic fun init$default (Lio/piano/android/id/PianoId$Companion;Ljava/lang/String;Ljava/lang/String;Lio/piano/android/consents/PianoConsents;ILjava/lang/Object;)Lio/piano/android/id/PianoIdClient; @@ -51,12 +41,6 @@ public final class io/piano/android/id/PianoId$Companion { public final fun isPianoIdUri (Landroid/net/Uri;)Z public final fun parsePianoIdToken (Landroid/net/Uri;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun parsePianoIdToken (Landroid/net/Uri;Lkotlin/jvm/functions/Function1;)V - public final fun putUserInfo (Ljava/lang/String;Lio/piano/android/id/models/PianoUserInfo;Lkotlin/jvm/functions/Function1;)V - public final fun refreshToken (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V - public final fun signIn ()Lio/piano/android/id/PianoIdClient$SignInContext; - public final fun signOut (Ljava/lang/String;)V - public final fun signOut (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V - public static synthetic fun signOut$default (Lio/piano/android/id/PianoId$Companion;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V } public final class io/piano/android/id/PianoIdActivity : androidx/appcompat/app/AppCompatActivity, io/piano/android/id/PianoIdJsInterface { diff --git a/id/id/src/main/java/io/piano/android/id/AidInterceptor.kt b/id/id/src/main/java/io/piano/android/id/AidInterceptor.kt index c671f54..b1b0754 100644 --- a/id/id/src/main/java/io/piano/android/id/AidInterceptor.kt +++ b/id/id/src/main/java/io/piano/android/id/AidInterceptor.kt @@ -4,16 +4,17 @@ import okhttp3.Interceptor import okhttp3.Response import java.io.IOException -internal class AidInterceptor(private val aid: String) : Interceptor { +internal class AidInterceptor( + private val aid: String, +) : Interceptor { @Throws(IOException::class) - override fun intercept(chain: Interceptor.Chain): Response { - return chain.proceed( - chain.request() - .newBuilder() - .header(AID_HEADER, aid) - .build() - ) - } + override fun intercept(chain: Interceptor.Chain): Response = chain.proceed( + chain.request() + .newBuilder() + .header(AID_HEADER, aid) + .build(), + ) + companion object { internal const val AID_HEADER = "piano-app-id" } diff --git a/id/id/src/main/java/io/piano/android/id/ConsentsDataProvider.kt b/id/id/src/main/java/io/piano/android/id/ConsentsDataProvider.kt index e916829..17c2a86 100644 --- a/id/id/src/main/java/io/piano/android/id/ConsentsDataProvider.kt +++ b/id/id/src/main/java/io/piano/android/id/ConsentsDataProvider.kt @@ -27,7 +27,7 @@ internal class ConsentsDataProvider( }?.let { Base64.encode( packedConsentAdapter.toJson(it).encodeToByteArray(), - Base64.URL_SAFE or Base64.NO_WRAP + Base64.URL_SAFE or Base64.NO_WRAP, ).decodeToString() } } diff --git a/id/id/src/main/java/io/piano/android/id/ObjectJsonAdapter.kt b/id/id/src/main/java/io/piano/android/id/ObjectJsonAdapter.kt index 9e4b946..be5a8ce 100644 --- a/id/id/src/main/java/io/piano/android/id/ObjectJsonAdapter.kt +++ b/id/id/src/main/java/io/piano/android/id/ObjectJsonAdapter.kt @@ -8,18 +8,16 @@ internal class ObjectJsonAdapter( private val delegate: JsonAdapter, private val longAdapter: JsonAdapter, ) : JsonAdapter() { - override fun fromJson(reader: JsonReader): Any? { - return if (reader.peek() == JsonReader.Token.NUMBER) { - runCatching { - longAdapter.fromJson(reader.peekJson()).also { - reader.skipValue() - } - }.recover { - delegate.fromJson(reader) - }.getOrNull() - } else { + override fun fromJson(reader: JsonReader): Any? = if (reader.peek() == JsonReader.Token.NUMBER) { + runCatching { + longAdapter.fromJson(reader.peekJson()).also { + reader.skipValue() + } + }.recover { delegate.fromJson(reader) - } + }.getOrNull() + } else { + delegate.fromJson(reader) } override fun toJson(writer: JsonWriter, value: Any?) = delegate.toJson(writer, value) diff --git a/id/id/src/main/java/io/piano/android/id/PianoId.kt b/id/id/src/main/java/io/piano/android/id/PianoId.kt index e58f70c..930a423 100644 --- a/id/id/src/main/java/io/piano/android/id/PianoId.kt +++ b/id/id/src/main/java/io/piano/android/id/PianoId.kt @@ -12,8 +12,6 @@ import io.piano.android.consents.models.Consent import io.piano.android.consents.models.Purpose import io.piano.android.id.models.ConsentData import io.piano.android.id.models.PianoIdToken -import io.piano.android.id.models.PianoUserInfo -import io.piano.android.id.models.PianoUserProfile import kotlinx.coroutines.suspendCancellableCoroutine import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl @@ -48,15 +46,15 @@ public class PianoId { Types.newParameterizedType( Map::class.java, Purpose::class.java, - Consent::class.java - ) + Consent::class.java, + ), ), moshi.adapter( Types.newParameterizedType( List::class.java, - ConsentData::class.java - ) - ) + ConsentData::class.java, + ), + ), ) val okHttpClient = OkHttpClient.Builder() .addInterceptor(ConsentsInterceptor(consentsDataProvider)) @@ -68,8 +66,8 @@ public class PianoId { HttpLoggingInterceptor.Level.BODY } else { HttpLoggingInterceptor.Level.NONE - } - ) + }, + ), ) .build() val retrofit = Retrofit.Builder() @@ -128,103 +126,6 @@ public class PianoId { NOT_INITIALIZED_MSG } - /** - * Gets preferences for authorization process - * - * @return {@link PianoIdClient.SignInContext} instance - * @throws IllegalStateException If you call it before {@link #init(String, String)} - */ - @Suppress("unused") // Public API. - @Throws(IllegalStateException::class) - @JvmStatic - @Deprecated( - "Use method directly from PianoIdClient instance, will be removed in future versions", - ReplaceWith("PianoId.getInstance().signIn()") - ) - public fun signIn(): PianoIdClient.SignInContext = getInstance().signIn() - - /** - * Sign out user by it's token - * - * @param accessToken User access token - * @param callback callback, which will receive sign-out result - */ - @Suppress("unused") // Public API. - @JvmStatic - @JvmOverloads - @Deprecated( - "Use method directly from PianoIdClient instance, will be removed in future versions", - ReplaceWith("PianoId.getInstance().signOut(accessToken, callback)") - ) - public fun signOut(accessToken: String, callback: PianoIdFuncCallback? = null) { - val signOutCallback = callback ?: {} - client?.signOut(accessToken, signOutCallback) - ?: signOutCallback(Result.failure(IllegalStateException(NOT_INITIALIZED_MSG))) - } - - /** - * Refresh user access token - * - * @param refreshToken User refresh token - * @param callback callback, which will receive result - */ - @Suppress("unused") // Public API. - @Throws(IllegalStateException::class) - @JvmStatic - @Deprecated( - "Use method directly from PianoIdClient instance, will be removed in future versions", - ReplaceWith("PianoId.getInstance().refreshToken(refreshToken, callback)") - ) - public fun refreshToken(refreshToken: String, callback: PianoIdFuncCallback) { - client?.refreshToken(refreshToken, callback) - ?: callback(Result.failure(IllegalStateException(NOT_INITIALIZED_MSG))) - } - - /** - * Gets user info - * - * @param accessToken User access token - * @param formName Form name, which stores data. Use null for default - * @param callback callback, which will receive result - */ - @Suppress("unused") // Public API. - @JvmStatic - @JvmOverloads - @Deprecated( - "Use method directly from PianoIdClient instance, will be removed in future versions", - ReplaceWith("PianoId.getInstance().getUserInfo(accessToken, formName, callback)") - ) - public fun getUserInfo( - accessToken: String, - formName: String? = null, - callback: PianoIdFuncCallback, - ) { - client?.getUserInfo(accessToken, formName, callback) - ?: callback(Result.failure(IllegalStateException(NOT_INITIALIZED_MSG))) - } - - /** - * Stores user info - * - * @param accessToken User access token - * @param newUserInfo New user info - * @param callback callback, which will receive result - */ - @Suppress("unused") // Public API. - @JvmStatic - @Deprecated( - "Use method directly from PianoIdClient instance, will be removed in future versions", - ReplaceWith("PianoId.getInstance().putUserInfo(accessToken, newUserInfo, callback)") - ) - public fun putUserInfo( - accessToken: String, - newUserInfo: PianoUserInfo, - callback: PianoIdFuncCallback, - ) { - client?.putUserInfo(accessToken, newUserInfo, callback) - ?: callback(Result.failure(IllegalStateException(NOT_INITIALIZED_MSG))) - } - @Suppress("unused") // Public API. @JvmStatic public fun Uri?.parsePianoIdToken(callback: PianoIdFuncCallback): Unit = diff --git a/id/id/src/main/java/io/piano/android/id/PianoIdActivity.kt b/id/id/src/main/java/io/piano/android/id/PianoIdActivity.kt index fb8eb04..294b68d 100644 --- a/id/id/src/main/java/io/piano/android/id/PianoIdActivity.kt +++ b/id/id/src/main/java/io/piano/android/id/PianoIdActivity.kt @@ -27,6 +27,7 @@ import io.piano.android.id.models.PianoIdToken import kotlinx.coroutines.launch import timber.log.Timber +@Suppress("ktlint:standard:class-signature") public class PianoIdActivity : AppCompatActivity(), PianoIdJsInterface { @VisibleForTesting @RestrictTo(RestrictTo.Scope.LIBRARY) @@ -58,6 +59,7 @@ public class PianoIdActivity : AppCompatActivity(), PianoIdJsInterface { intent?.process() onBackPressedDispatcher.addCallback(webviewBackPressedCallback) with(binding) { + root.handleEdgeToEdge() webview.apply { savedInstanceState?.let { restoreState(it) } settings.apply { @@ -105,7 +107,7 @@ public class PianoIdActivity : AppCompatActivity(), PianoIdJsInterface { val isPianoIdRedirectUrl = Uri.parse(url).isPianoIdUri() if (isPianoIdRedirectUrl) { setFailureResultData( - IllegalStateException("User already authorized, call signOut before login") + IllegalStateException("User already authorized, call signOut before login"), ) } progressBar.show() @@ -175,7 +177,7 @@ public class PianoIdActivity : AppCompatActivity(), PianoIdJsInterface { private fun setSuccessResultData(token: PianoIdToken, isNewUser: Boolean) { setResult( Activity.RESULT_OK, - Intent().putExtra(PianoId.KEY_TOKEN, token).putExtra(PianoId.KEY_IS_NEW_USER, isNewUser) + Intent().putExtra(PianoId.KEY_TOKEN, token).putExtra(PianoId.KEY_IS_NEW_USER, isNewUser), ) client.authCallback?.invoke(PianoIdAuthResult.success(token, isNewUser)) finish() diff --git a/id/id/src/main/java/io/piano/android/id/PianoIdAuthResultContract.kt b/id/id/src/main/java/io/piano/android/id/PianoIdAuthResultContract.kt index 27d7fdb..c9be1c7 100644 --- a/id/id/src/main/java/io/piano/android/id/PianoIdAuthResultContract.kt +++ b/id/id/src/main/java/io/piano/android/id/PianoIdAuthResultContract.kt @@ -24,7 +24,7 @@ public class PianoIdAuthResultContract : ActivityResultContract, t: Throwable) { // don't change predefined } - } + }, ) } @@ -279,7 +279,7 @@ public class PianoIdClient internal constructor( api.exchangeAuthCode( hostUrl.newBuilder().encodedPath(EXCHANGE_AUTH_CODE_PATH).build().toString(), aid, - authCode + authCode, ).enqueue(callback.asRetrofitCallback()) } @@ -301,7 +301,7 @@ public class PianoIdClient internal constructor( if (oauthProviders.isNotEmpty()) { addQueryParameter( PARAM_OAUTH_PROVIDERS, - oauthProviders.keys.joinToString(separator = ",") + oauthProviders.keys.joinToString(separator = ","), ) } } @@ -347,7 +347,7 @@ public class PianoIdClient internal constructor( internal fun buildResultJsCommand(provider: String, token: String): String { val socialTokenData = socialTokenDataAdapter.toJson( - SocialTokenData(provider.uppercase(Locale.US), token, aid) + SocialTokenData(provider.uppercase(Locale.US), token, aid), ) return "(function(){window.PianoIDMobileSDK.socialLoginCallback('$socialTokenData')})()" } @@ -368,7 +368,7 @@ public class PianoIdClient internal constructor( invoke( runCatching { response.bodyOrThrow() - } + }, ) } diff --git a/id/id/src/main/java/io/piano/android/id/PianoIdJavascriptDelegate.kt b/id/id/src/main/java/io/piano/android/id/PianoIdJavascriptDelegate.kt index 136f445..c16e5f5 100644 --- a/id/id/src/main/java/io/piano/android/id/PianoIdJavascriptDelegate.kt +++ b/id/id/src/main/java/io/piano/android/id/PianoIdJavascriptDelegate.kt @@ -6,7 +6,8 @@ import java.lang.ref.WeakReference internal class PianoIdJavascriptDelegate( internalDelegate: PianoIdJsInterface, publicDelegate: PianoIdJs?, -) : PianoIdJsInterface, PianoIdJs { +) : PianoIdJsInterface, + PianoIdJs { private val internalJsReference: WeakReference = WeakReference(internalDelegate) private val publicJsReference: WeakReference = WeakReference(publicDelegate) diff --git a/id/id/src/main/java/io/piano/android/id/PianoIdJsonAdapterFactory.kt b/id/id/src/main/java/io/piano/android/id/PianoIdJsonAdapterFactory.kt index 3972c41..5209790 100644 --- a/id/id/src/main/java/io/piano/android/id/PianoIdJsonAdapterFactory.kt +++ b/id/id/src/main/java/io/piano/android/id/PianoIdJsonAdapterFactory.kt @@ -11,8 +11,9 @@ public class PianoIdJsonAdapterFactory : JsonAdapter.Factory { PianoIdToken::class.java -> PianoIdTokenJsonAdapter(moshi) Any::class.java -> ObjectJsonAdapter( moshi.nextAdapter(this, Any::class.java, annotations), - moshi.adapter(Long::class.java) + moshi.adapter(Long::class.java), ) + else -> null } } diff --git a/id/id/src/main/java/io/piano/android/id/PianoIdTokenJsonAdapter.kt b/id/id/src/main/java/io/piano/android/id/PianoIdTokenJsonAdapter.kt index 051b6a4..d8122cd 100644 --- a/id/id/src/main/java/io/piano/android/id/PianoIdTokenJsonAdapter.kt +++ b/id/id/src/main/java/io/piano/android/id/PianoIdTokenJsonAdapter.kt @@ -16,7 +16,7 @@ public class PianoIdTokenJsonAdapter( ACCESS_TOKEN, ACCESS_TOKEN_CAMEL, REFRESH_TOKEN, - REFRESH_TOKEN_CAMEL + REFRESH_TOKEN_CAMEL, ) private val stringAdapter: JsonAdapter = moshi.adapter(String::class.java) @@ -28,8 +28,8 @@ public class PianoIdTokenJsonAdapter( Types.newParameterizedType( Map::class.java, String::class.java, - Any::class.java - ) + Any::class.java, + ), ) } @@ -44,13 +44,13 @@ public class PianoIdTokenJsonAdapter( accessToken = stringAdapter.fromJson(reader) ?: throw Util.unexpectedNull( ACCESS_TOKEN_CAMEL, ACCESS_TOKEN, - reader + reader, ) 2, 3 -> refreshToken = stringAdapter.fromJson(reader) ?: throw Util.unexpectedNull( REFRESH_TOKEN_CAMEL, REFRESH_TOKEN, - reader + reader, ) -1 -> { // Unknown name, skip it. @@ -61,12 +61,12 @@ public class PianoIdTokenJsonAdapter( } endObject() val jwtFields = jwtAdapter.fromJson( - Base64.decode(accessToken!!.split("\\.".toRegex())[1], Base64.URL_SAFE).decodeToString() + Base64.decode(accessToken!!.split("\\.".toRegex())[1], Base64.URL_SAFE).decodeToString(), ) PianoIdToken( accessToken ?: throw Util.missingProperty(ACCESS_TOKEN_CAMEL, ACCESS_TOKEN, reader), refreshToken ?: "", - jwtFields ?: emptyMap() + jwtFields ?: emptyMap(), ) } } diff --git a/id/id/src/main/java/io/piano/android/id/UserAgentInterceptor.kt b/id/id/src/main/java/io/piano/android/id/UserAgentInterceptor.kt index 8df0c45..865f6d5 100644 --- a/id/id/src/main/java/io/piano/android/id/UserAgentInterceptor.kt +++ b/id/id/src/main/java/io/piano/android/id/UserAgentInterceptor.kt @@ -4,14 +4,14 @@ import okhttp3.Interceptor import okhttp3.Response import java.io.IOException -internal class UserAgentInterceptor(private val userAgent: String) : Interceptor { +internal class UserAgentInterceptor( + private val userAgent: String, +) : Interceptor { @Throws(IOException::class) - override fun intercept(chain: Interceptor.Chain): Response { - return chain.proceed( - chain.request() - .newBuilder() - .header("User-Agent", userAgent) - .build() - ) - } + override fun intercept(chain: Interceptor.Chain): Response = chain.proceed( + chain.request() + .newBuilder() + .header("User-Agent", userAgent) + .build(), + ) } diff --git a/id/id/src/main/java/io/piano/android/id/Utils.kt b/id/id/src/main/java/io/piano/android/id/Utils.kt new file mode 100644 index 0000000..9c651e7 --- /dev/null +++ b/id/id/src/main/java/io/piano/android/id/Utils.kt @@ -0,0 +1,24 @@ +package io.piano.android.id + +import android.os.Build +import android.view.View +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding + +internal fun View.handleEdgeToEdge() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets -> + val bars = insets.getInsets( + WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout(), + ) + v.updatePadding( + left = bars.left, + top = bars.top, + right = bars.right, + bottom = bars.bottom, + ) + WindowInsetsCompat.CONSUMED + } + } +} diff --git a/id/id/src/main/java/io/piano/android/id/models/OAuthResult.kt b/id/id/src/main/java/io/piano/android/id/models/OAuthResult.kt index 913840e..c2d15a2 100644 --- a/id/id/src/main/java/io/piano/android/id/models/OAuthResult.kt +++ b/id/id/src/main/java/io/piano/android/id/models/OAuthResult.kt @@ -1,5 +1,8 @@ package io.piano.android.id.models public sealed class OAuthResult -public class OAuthSuccessResult(public val provider: String, public val token: String) : OAuthResult() +public class OAuthSuccessResult( + public val provider: String, + public val token: String, +) : OAuthResult() public data object OAuthCancelledResult : OAuthResult() diff --git a/id/id/src/main/java/io/piano/android/id/models/PianoUserInfo.kt b/id/id/src/main/java/io/piano/android/id/models/PianoUserInfo.kt index fa47c1a..2505a23 100644 --- a/id/id/src/main/java/io/piano/android/id/models/PianoUserInfo.kt +++ b/id/id/src/main/java/io/piano/android/id/models/PianoUserInfo.kt @@ -19,5 +19,5 @@ internal fun PianoUserInfo.toProfileUpdateRequest() = ProfileUpdateRequest( formName, customFields.map { CustomField(fieldName = it.key, value = it.value) - } + }, ) diff --git a/id/id/src/test/java/android/util/SparseArray.kt b/id/id/src/test/java/android/util/SparseArray.kt index 9f72a83..2718b8c 100644 --- a/id/id/src/test/java/android/util/SparseArray.kt +++ b/id/id/src/test/java/android/util/SparseArray.kt @@ -17,11 +17,7 @@ open class SparseArray { map[key] = value } - operator fun get(key: Int): E? { - return map[key] - } + operator fun get(key: Int): E? = map[key] - fun get(key: Int, defaultValue: E): E { - return get(key) ?: defaultValue - } + fun get(key: Int, defaultValue: E): E = get(key) ?: defaultValue } diff --git a/id/id/src/test/java/io/piano/android/id/AidInterceptorTest.kt b/id/id/src/test/java/io/piano/android/id/AidInterceptorTest.kt index 6322907..ac1a397 100644 --- a/id/id/src/test/java/io/piano/android/id/AidInterceptorTest.kt +++ b/id/id/src/test/java/io/piano/android/id/AidInterceptorTest.kt @@ -34,7 +34,7 @@ class AidInterceptorTest { .newCall( Request.Builder() .url(mockWebServer.url("/")) - .build() + .build(), ).execute() assertEquals(AID_VALUE, mockWebServer.takeRequest().getHeader(AidInterceptor.AID_HEADER)) } diff --git a/id/id/src/test/java/io/piano/android/id/ConsentsInterceptorTest.kt b/id/id/src/test/java/io/piano/android/id/ConsentsInterceptorTest.kt index 218f496..7df56d2 100644 --- a/id/id/src/test/java/io/piano/android/id/ConsentsInterceptorTest.kt +++ b/id/id/src/test/java/io/piano/android/id/ConsentsInterceptorTest.kt @@ -39,7 +39,7 @@ class ConsentsInterceptorTest { .newCall( Request.Builder() .url(mockWebServer.url("/")) - .build() + .build(), ).execute() assertEquals(CONSENTS_VALUE, mockWebServer.takeRequest().getHeader(ConsentsInterceptor.CONSENTS_HEADER)) } diff --git a/id/id/src/test/java/io/piano/android/id/PianoIdClientTest.kt b/id/id/src/test/java/io/piano/android/id/PianoIdClientTest.kt index 9258d7d..0b1a8a8 100644 --- a/id/id/src/test/java/io/piano/android/id/PianoIdClientTest.kt +++ b/id/id/src/test/java/io/piano/android/id/PianoIdClientTest.kt @@ -105,7 +105,7 @@ class PianoIdClientTest { @Test fun getAuthEndpointResponseSuccess() = getAuthEndpoint { retrofitCallback -> val data: HostResponse = spy( - HostResponse(url.toString(), 0, null, null) + HostResponse(url.toString(), 0, null, null), ) { on { hasError } doReturn false on { error } doReturn DUMMY diff --git a/id/id/src/test/java/io/piano/android/id/UserAgentInterceptorTest.kt b/id/id/src/test/java/io/piano/android/id/UserAgentInterceptorTest.kt index f5b7edd..0898d05 100644 --- a/id/id/src/test/java/io/piano/android/id/UserAgentInterceptorTest.kt +++ b/id/id/src/test/java/io/piano/android/id/UserAgentInterceptorTest.kt @@ -34,7 +34,7 @@ class UserAgentInterceptorTest { .newCall( Request.Builder() .url(mockWebServer.url("/")) - .build() + .build(), ).execute() assertEquals(USER_AGENT_VALUE, mockWebServer.takeRequest().getHeader("User-Agent")) } diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 0bb7c7c..1a263bc 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -38,7 +38,7 @@ android { "PIANO_AID" to aid.lowercase(Locale.getDefault()), "FB_APP_ID" to "fb$fbAppId", "FB_APP_SCHEME" to "fb$fbAppId", - "FB_APP_TOKEN" to fbAppToken + "FB_APP_TOKEN" to fbAppToken, ) } signingConfigs { diff --git a/sample/src/main/java/io/piano/sample/ComposerActivity.kt b/sample/src/main/java/io/piano/sample/ComposerActivity.kt index ce67592..a6f4022 100644 --- a/sample/src/main/java/io/piano/sample/ComposerActivity.kt +++ b/sample/src/main/java/io/piano/sample/ComposerActivity.kt @@ -46,13 +46,14 @@ class ComposerActivity : AppCompatActivity() { null -> Snackbar.make( findViewById(R.id.app_bar), "OAuth cancelled", - Snackbar.LENGTH_SHORT + Snackbar.LENGTH_SHORT, ).show() + is PianoIdAuthSuccessResult -> setAccessToken(r.token) is PianoIdAuthFailureResult -> Snackbar.make( findViewById(R.id.app_bar), r.exception.message ?: "Unknown error", - Snackbar.LENGTH_SHORT + Snackbar.LENGTH_SHORT, ).show() } } @@ -92,27 +93,27 @@ class ComposerActivity : AppCompatActivity() { eventExecutionContext.userSegments.standard?.let { Timber.d( "Standard user segments are ${it.segments.joinToString(prefix = "[", postfix = "]")}," + - " expires at ${it.expiresAt}" + " expires at ${it.expiresAt}", ) } Toast.makeText( this, "[${Thread.currentThread().name}] User = ${eventData.user}", - Toast.LENGTH_LONG + Toast.LENGTH_LONG, ).show() }, UserSegmentListener { (_, _, eventData) -> Toast.makeText( this, "[${Thread.currentThread().name}] User state = ${eventData.state}", - Toast.LENGTH_LONG + Toast.LENGTH_LONG, ).show() }, ShowLoginListener { (_, _, eventData) -> Toast.makeText( this, "[${Thread.currentThread().name}] ${eventData.userProvider}", - Toast.LENGTH_LONG + Toast.LENGTH_LONG, ).show() signIn() }, @@ -133,7 +134,7 @@ class ComposerActivity : AppCompatActivity() { Toast.makeText( this, "[${Thread.currentThread().name}] ${event.eventData}", - Toast.LENGTH_LONG + Toast.LENGTH_LONG, ).show() showTemplateController = ShowTemplateController( event, @@ -148,7 +149,7 @@ class ComposerActivity : AppCompatActivity() { override fun login(eventData: String) { signIn() } - } + }, ) showTemplateController?.show(this) }, @@ -161,7 +162,7 @@ class ComposerActivity : AppCompatActivity() { widgetId = $widgetId, siteId = $siteId """.trimIndent(), - Toast.LENGTH_LONG + Toast.LENGTH_LONG, ).show() } ShowRecommendationsController(event).show(this) @@ -170,14 +171,14 @@ class ComposerActivity : AppCompatActivity() { Toast.makeText( this, "[${Thread.currentThread().name}] ${event.eventData}", - Toast.LENGTH_LONG + Toast.LENGTH_LONG, ).show() showFormControllers.add( ShowFormController(event, prefsStorage.pianoIdToken?.accessToken ?: "") { signIn() }.also { it.show(this) - } + }, ) }, SetResponseVariableListener { (_, _, eventData) -> @@ -187,7 +188,7 @@ class ComposerActivity : AppCompatActivity() { Toast.makeText( this, "[${Thread.currentThread().name}] $message", - Toast.LENGTH_LONG + Toast.LENGTH_LONG, ).show() }, NonSiteListener { (_, eventExecutionContext) -> @@ -202,13 +203,13 @@ class ComposerActivity : AppCompatActivity() { """.trimIndent() } ?: "[${Thread.currentThread().name}] Active meters are null or empty!" Toast.makeText(this, message, Toast.LENGTH_LONG).show() - } + }, ) Composer.getInstance().getExperience(request, listeners) { exception: ComposerException -> Toast.makeText( this, "[${Thread.currentThread().name}] ${exception.cause?.message ?: exception.message}", - Toast.LENGTH_LONG + Toast.LENGTH_LONG, ).show() } } diff --git a/sample/src/main/java/io/piano/sample/ComposerScrollDepthActivity.kt b/sample/src/main/java/io/piano/sample/ComposerScrollDepthActivity.kt index 2f1ec81..1398552 100644 --- a/sample/src/main/java/io/piano/sample/ComposerScrollDepthActivity.kt +++ b/sample/src/main/java/io/piano/sample/ComposerScrollDepthActivity.kt @@ -43,7 +43,7 @@ class ComposerScrollDepthActivity : AppCompatActivity() { } } } - } + }, ) } } @@ -53,12 +53,12 @@ class ComposerScrollDepthActivity : AppCompatActivity() { .build() Composer.getInstance().getExperience( request, - listOf(showTemplateListener) + listOf(showTemplateListener), ) { exception: ComposerException -> Toast.makeText( this@ComposerScrollDepthActivity, "[${Thread.currentThread().name}] ${exception.cause?.message ?: exception.message}", - Toast.LENGTH_LONG + Toast.LENGTH_LONG, ).show() } } diff --git a/sample/src/main/java/io/piano/sample/MainActivity.kt b/sample/src/main/java/io/piano/sample/MainActivity.kt index 87f9592..83ae27b 100644 --- a/sample/src/main/java/io/piano/sample/MainActivity.kt +++ b/sample/src/main/java/io/piano/sample/MainActivity.kt @@ -77,13 +77,14 @@ class MainActivity : AppCompatActivity() { Timber.d("We processed deep link") } binding.apply { + root.handleEdgeToEdge() buttonPianoIdLogin.setOnClickListener { - authResult.launch(PianoId.signIn()) + authResult.launch(PianoId.getInstance().signIn()) } buttonPianoIdLogout.setOnClickListener { signOut() } buttonPianoIdRefreshToken.setOnClickListener { prefsStorage.pianoIdToken?.run { - PianoId.refreshToken(refreshToken) { r -> + PianoId.getInstance().refreshToken(refreshToken) { r -> r.onSuccess { setAccessToken(it) }.onFailure { @@ -96,16 +97,16 @@ class MainActivity : AppCompatActivity() { startActivity( Intent( this@MainActivity, - ComposerActivity::class.java - ) + ComposerActivity::class.java, + ), ) } buttonComposerScrollDepth.setOnClickListener { startActivity( Intent( this@MainActivity, - ComposerScrollDepthActivity::class.java - ) + ComposerScrollDepthActivity::class.java, + ), ) } buttonComposerEdge.setOnClickListener { @@ -127,37 +128,39 @@ class MainActivity : AppCompatActivity() { } .post(edgeBody) .build() - okHttpClient.newCall(edgeRequest).enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - showError(e) - } + okHttpClient.newCall(edgeRequest).enqueue( + object : Callback { + override fun onFailure(call: Call, e: IOException) { + showError(e) + } - override fun onResponse(call: Call, response: Response) { - val cookies = Cookie.parseAll(BuildConfig.SITE_URL.toHttpUrl(), response.headers) - val request = ExperienceRequest.Builder() - .url(BuildConfig.SITE_URL) - .edgeResult( - EdgeResult( - cookies.getCookieValue("__tbc"), - cookies.getCookieValue("xbc"), - cookies.getCookieValue("_pcer") + override fun onResponse(call: Call, response: Response) { + val cookies = Cookie.parseAll(BuildConfig.SITE_URL.toHttpUrl(), response.headers) + val request = ExperienceRequest.Builder() + .url(BuildConfig.SITE_URL) + .edgeResult( + EdgeResult( + cookies.getCookieValue("__tbc"), + cookies.getCookieValue("xbc"), + cookies.getCookieValue("_pcer"), + ), ) - ) - .debug(true) - .build() - val eventsListener: EventsListener = { - val eventTypes = it.joinToString(prefix = "[", postfix = "]") { event -> - event.eventData.toString() + .debug(true) + .build() + val eventsListener: EventsListener = { + val eventTypes = it.joinToString(prefix = "[", postfix = "]") { event -> + event.eventData.toString() + } + val message = "Got events: $eventTypes" + Timber.d(message) + showMessage(message) + } + Composer.getInstance().getExperience(request, eventsListener) { + showError(it) } - val message = "Got events: $eventTypes" - Timber.d(message) - showMessage(message) - } - Composer.getInstance().getExperience(request, eventsListener) { - showError(it) } - } - }) + }, + ) } buttonComposerClearStorage.setOnClickListener { Composer.getInstance().clearStoredData() @@ -191,21 +194,23 @@ class MainActivity : AppCompatActivity() { } val userFields = token.info.map { (key, value) -> "$key = $value" }.joinToString(prefix = "[", postfix = "]") Timber.d("Token has these fields: %s", userFields) - PianoId.getInstance().getUserInfo(token.accessToken) { r -> - val customFields = r.getOrNull() - ?.customFields - ?.joinToString(prefix = "[", postfix = "]") { "${it.fieldName} = ${it.value}" } - Timber.d("User custom fields = $customFields") - val newUserInfo = PianoUserInfo("new_form") - .customField("test0", listOf("value")) - .customField("test1", "test") - .customField("test2", true) - .customField("test3", 5) - PianoId.getInstance().putUserInfo(token.accessToken, newUserInfo) { r2 -> - val newCustomFields = r2.getOrNull() + with(PianoId.getInstance()) { + getUserInfo(token.accessToken) { r -> + val customFields = r.getOrNull() ?.customFields ?.joinToString(prefix = "[", postfix = "]") { "${it.fieldName} = ${it.value}" } - Timber.d("Updated user custom fields = $newCustomFields") + Timber.d("User custom fields = $customFields") + val newUserInfo = PianoUserInfo("new_form") + .customField("test0", listOf("value")) + .customField("test1", "test") + .customField("test2", true) + .customField("test3", 5) + putUserInfo(token.accessToken, newUserInfo) { r2 -> + val newCustomFields = r2.getOrNull() + ?.customFields + ?.joinToString(prefix = "[", postfix = "]") { "${it.fieldName} = ${it.value}" } + Timber.d("Updated user custom fields = $newCustomFields") + } } } Composer.getInstance().userToken(token.accessToken) diff --git a/sample/src/main/java/io/piano/sample/PianoSampleApplication.kt b/sample/src/main/java/io/piano/sample/PianoSampleApplication.kt index e00b14d..58c4bf0 100644 --- a/sample/src/main/java/io/piano/sample/PianoSampleApplication.kt +++ b/sample/src/main/java/io/piano/sample/PianoSampleApplication.kt @@ -36,8 +36,8 @@ class PianoSampleApplication : MultiDexApplication() { val pianoConsents = PianoConsents.init( this, ConsentConfiguration( - requireConsent = true - ) + requireConsent = true, + ), ) PianoId.init(PIANO_ID_ENDPOINT, BuildConfig.PIANO_AID, pianoConsents) .with { r -> @@ -51,11 +51,13 @@ class PianoSampleApplication : MultiDexApplication() { is PianoIdAuthFailureResult -> Timber.e(r.exception) } } - .with(object : PianoIdJs { - override fun customEvent(eventData: String) { - Timber.d("Custom event: %s", eventData) - } - }) + .with( + object : PianoIdJs { + override fun customEvent(eventData: String) { + Timber.d("Custom event: %s", eventData) + } + }, + ) .with(GoogleOAuthProvider()) .with(FacebookOAuthProvider()) // Use this one if you want Piano C1X integration @@ -77,12 +79,12 @@ class PianoSampleApplication : MultiDexApplication() { val COMPOSER_ENDPOINT = when { BuildConfig.PIANO_ENDPOINT.isNotEmpty() -> Endpoint( BuildConfig.PIANO_ENDPOINT, - BuildConfig.PIANO_ENDPOINT + BuildConfig.PIANO_ENDPOINT, ) BuildConfig.PIANO_QA_PREFIX.isNotEmpty() -> Endpoint( "https://c2-${BuildConfig.PIANO_QA_PREFIX}.qa.piano.dev/", - "https://${BuildConfig.PIANO_QA_PREFIX}.qa.piano.dev/" + "https://${BuildConfig.PIANO_QA_PREFIX}.qa.piano.dev/", ) else -> Endpoint.SANDBOX diff --git a/sample/src/main/java/io/piano/sample/PrefsStorage.kt b/sample/src/main/java/io/piano/sample/PrefsStorage.kt index 98c962b..0b58ae1 100644 --- a/sample/src/main/java/io/piano/sample/PrefsStorage.kt +++ b/sample/src/main/java/io/piano/sample/PrefsStorage.kt @@ -9,7 +9,10 @@ import com.squareup.moshi.Moshi import io.piano.android.id.models.PianoIdToken import timber.log.Timber -class PrefsStorage(context: Context, moshi: Moshi) { +class PrefsStorage( + context: Context, + moshi: Moshi, +) { private val sharedPreferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) private val pianoIdTokenJsonAdapter: JsonAdapter = moshi.adapter(PianoIdToken::class.java).nullSafe() diff --git a/sample/src/main/java/io/piano/sample/SimpleDependenciesProvider.kt b/sample/src/main/java/io/piano/sample/SimpleDependenciesProvider.kt index 2a942eb..f8ba009 100644 --- a/sample/src/main/java/io/piano/sample/SimpleDependenciesProvider.kt +++ b/sample/src/main/java/io/piano/sample/SimpleDependenciesProvider.kt @@ -6,13 +6,15 @@ import io.piano.android.id.PianoIdJsonAdapterFactory import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor -class SimpleDependenciesProvider private constructor(context: Context) { +class SimpleDependenciesProvider private constructor( + context: Context, +) { val appContext: Context = context.applicationContext val moshi: Moshi = Moshi.Builder().add(PianoIdJsonAdapterFactory()).build() val prefsStorage: PrefsStorage = PrefsStorage(appContext, moshi) val okHttpClient: OkHttpClient = OkHttpClient.Builder() .addInterceptor( - HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY) + HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY), ) .build() diff --git a/sample/src/main/java/io/piano/sample/Utils.kt b/sample/src/main/java/io/piano/sample/Utils.kt new file mode 100644 index 0000000..018ced8 --- /dev/null +++ b/sample/src/main/java/io/piano/sample/Utils.kt @@ -0,0 +1,24 @@ +package io.piano.sample + +import android.os.Build +import android.view.View +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding + +internal fun View.handleEdgeToEdge() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets -> + val bars = insets.getInsets( + WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout(), + ) + v.updatePadding( + left = bars.left, + top = bars.top, + right = bars.right, + bottom = bars.bottom, + ) + WindowInsetsCompat.CONSUMED + } + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 85021ea..87ac03a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -35,5 +35,5 @@ include( ":id:id-oauth-google", ":show-helper", ":show-custom-form", - ":sample" + ":sample", ) diff --git a/show-custom-form/src/main/java/io/piano/android/showform/EventData.kt b/show-custom-form/src/main/java/io/piano/android/showform/EventData.kt index 89c9f21..d7867a3 100644 --- a/show-custom-form/src/main/java/io/piano/android/showform/EventData.kt +++ b/show-custom-form/src/main/java/io/piano/android/showform/EventData.kt @@ -3,4 +3,7 @@ package io.piano.android.showform import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -internal class EventData(val event: String, val params: String? = null) +internal class EventData( + val event: String, + val params: String? = null, +) diff --git a/show-custom-form/src/main/java/io/piano/android/showform/ShowFormController.kt b/show-custom-form/src/main/java/io/piano/android/showform/ShowFormController.kt index d0903bb..d91b640 100644 --- a/show-custom-form/src/main/java/io/piano/android/showform/ShowFormController.kt +++ b/show-custom-form/src/main/java/io/piano/android/showform/ShowFormController.kt @@ -26,7 +26,7 @@ public class ShowFormController( private val loginCallback: () -> Unit, ) : BaseShowController( event.eventData, - ShowFormJs(event.eventData.formName, event.eventExecutionContext.trackingId, loginCallback) + ShowFormJs(event.eventData.formName, event.eventExecutionContext.trackingId, loginCallback), ) { private var checkProfileAtTokenChange: Boolean = false private val trackingId = event.eventExecutionContext.trackingId diff --git a/show-custom-form/src/main/java/io/piano/android/showform/ShowFormDialogFragment.kt b/show-custom-form/src/main/java/io/piano/android/showform/ShowFormDialogFragment.kt index e96f7ca..b8e8d19 100644 --- a/show-custom-form/src/main/java/io/piano/android/showform/ShowFormDialogFragment.kt +++ b/show-custom-form/src/main/java/io/piano/android/showform/ShowFormDialogFragment.kt @@ -59,7 +59,7 @@ public class ShowFormDialogFragment : BaseShowDialogFragment { val javascriptInterface = jsInterface as? ShowFormJs ?: ShowFormJs(formName, trackingId) prepare( javascriptInterface, - this@ShowFormDialogFragment + this@ShowFormDialogFragment, ) } diff --git a/show-custom-form/src/main/java/io/piano/android/showform/ShowFormJs.kt b/show-custom-form/src/main/java/io/piano/android/showform/ShowFormJs.kt index e339fda..6a832cd 100644 --- a/show-custom-form/src/main/java/io/piano/android/showform/ShowFormJs.kt +++ b/show-custom-form/src/main/java/io/piano/android/showform/ShowFormJs.kt @@ -48,7 +48,7 @@ public class ShowFormJs( private fun updateToken() { executeJavascript( """PianoIDMobileSDK.messageCallback('{"event":"setToken","params":"$token"}')""", - 200 + 200, ) }