Skip to content

Commit

Permalink
Merge branch 'master' into retenogit/master
Browse files Browse the repository at this point in the history
  • Loading branch information
Ilia-Solodiankin committed Mar 27, 2024
2 parents 665fff6 + 6170251 commit ef9bfc3
Show file tree
Hide file tree
Showing 105 changed files with 3,123 additions and 88 deletions.
6 changes: 5 additions & 1 deletion RetenoSdkCore/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ android {
minSdk globalConfig.androidMinSdkVersion
targetSdk globalConfig.androidTargetSdkVersion

android.buildFeatures.buildConfig true

consumerProguardFiles "consumer-rules.pro"

buildConfigField "String", "SQL_PASSWORD", sdkProps['sql.password']
Expand Down Expand Up @@ -60,6 +62,9 @@ android {
}

testOptions {
unitTests.all {
jvmArgs "--add-opens=java.base/java.time=ALL-UNNAMED"
}
unitTests {
includeAndroidResources = true
}
Expand All @@ -75,7 +80,6 @@ dependencies {
implementation "androidx.core:core-ktx:1.9.0"
implementation 'androidx.cardview:cardview:1.0.0'
compileOnly "com.google.firebase:firebase-messaging-ktx:23.1.2"

implementation "net.zetetic:android-database-sqlcipher:4.5.2"
implementation "androidx.sqlite:sqlite:2.1.0"

Expand Down
5 changes: 5 additions & 0 deletions RetenoSdkCore/src/main/java/com/reteno/core/Reteno.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ interface Reteno {
*/
fun updatePushPermissionStatus()

/**
*
*/
fun pauseInAppMessages(isPaused: Boolean)

/**
* Sends stored data without waiting for a send queue.
* But not more often than [com.reteno.core.domain.controller.ScheduleController.Companion.FORCE_PUSH_MIN_DELAY] millis.
Expand Down
5 changes: 5 additions & 0 deletions RetenoSdkCore/src/main/java/com/reteno/core/RetenoConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.reteno.core

class RetenoConfig @JvmOverloads constructor(
var isPausedInAppMessages: Boolean = false
)
25 changes: 22 additions & 3 deletions RetenoSdkCore/src/main/java/com/reteno/core/RetenoImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ package com.reteno.core

import android.app.Activity
import android.app.Application
import android.app.NotificationManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.util.Log
import com.reteno.core.di.ServiceLocator
import com.reteno.core.domain.controller.ScreenTrackingController
import com.reteno.core.domain.model.ecom.EcomEvent
Expand All @@ -21,7 +20,11 @@ import com.reteno.core.util.Constants.BROADCAST_ACTION_RETENO_APP_RESUME
import com.reteno.core.view.iam.IamView


class RetenoImpl(application: Application, accessKey: String) : RetenoLifecycleCallbacks, Reteno {
class RetenoImpl @JvmOverloads constructor(
application: Application,
accessKey: String,
private val config: RetenoConfig = RetenoConfig()
) : RetenoLifecycleCallbacks, Reteno {

init {
/*@formatter:off*/ Logger.i(TAG, "RetenoImpl(): ", "context = [" , application , "]")
Expand All @@ -36,6 +39,8 @@ class RetenoImpl(application: Application, accessKey: String) : RetenoLifecycleC
private val contactController by lazy { serviceLocator.contactControllerProvider.get() }
private val scheduleController by lazy { serviceLocator.scheduleControllerProvider.get() }
private val eventController by lazy { serviceLocator.eventsControllerProvider.get() }
private val iamController by lazy { serviceLocator.iamControllerProvider.get() }
private val sessionHandler by lazy { serviceLocator.retenoSessionHandlerProvider.get() }

override val appInbox by lazy { serviceLocator.appInboxProvider.get() }
override val recommendation by lazy { serviceLocator.recommendationProvider.get() }
Expand All @@ -48,6 +53,8 @@ class RetenoImpl(application: Application, accessKey: String) : RetenoLifecycleC
clearOldData()
contactController.checkIfDeviceRegistered()
sendAppResumeBroadcast()
pauseInAppMessages(config.isPausedInAppMessages)
fetchInAppMessages()
} catch (t: Throwable) {
/*@formatter:off*/ Logger.e(TAG, "init(): ", t)
/*@formatter:on*/
Expand All @@ -71,6 +78,7 @@ class RetenoImpl(application: Application, accessKey: String) : RetenoLifecycleC
/*@formatter:on*/
try {
contactController.checkIfDeviceRequestSentThisSession()
sessionHandler.start()
startPushScheduler()
iamView.resume(activity)
} catch (ex: Throwable) {
Expand All @@ -86,6 +94,7 @@ class RetenoImpl(application: Application, accessKey: String) : RetenoLifecycleC
/*@formatter:off*/ Logger.i(TAG, "pause(): ", "activity = [" , activity , "]")
/*@formatter:on*/
try {
sessionHandler.stop()
stopPushScheduler()
iamView.pause(activity)
} catch (ex: Throwable) {
Expand All @@ -102,6 +111,12 @@ class RetenoImpl(application: Application, accessKey: String) : RetenoLifecycleC
/*@formatter:on*/
}

private fun fetchInAppMessages() {
iamController.setIamView(iamView)
eventController.setIamController(iamController)
iamController.getInAppMessages()
}

private fun sendAppResumeBroadcast() {
val intent =
Intent(BROADCAST_ACTION_RETENO_APP_RESUME).setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
Expand Down Expand Up @@ -235,6 +250,10 @@ class RetenoImpl(application: Application, accessKey: String) : RetenoLifecycleC
}
}

override fun pauseInAppMessages(isPaused: Boolean) {
iamController.pauseInAppMessages(isPaused)
}

override fun forcePushData() {
if (!isOsVersionSupported()) {
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import com.reteno.core.data.local.database.schema.DbSchema.DATABASE_NAME
import com.reteno.core.data.local.database.schema.DbSchema.DATABASE_VERSION
import com.reteno.core.data.local.database.schema.DeviceSchema
import com.reteno.core.data.local.database.schema.EventsSchema
import com.reteno.core.data.local.database.schema.InAppInteractionSchema
import com.reteno.core.data.local.database.schema.InAppMessageSchema
import com.reteno.core.data.local.database.schema.InteractionSchema
import com.reteno.core.data.local.database.schema.LogEventSchema
import com.reteno.core.data.local.database.schema.RecomEventsSchema
Expand Down Expand Up @@ -143,13 +145,16 @@ internal class RetenoDatabaseImpl(private val context: Context) : RetenoDatabase
db.execSQL(UserSchema.UserAttributesSchema.SQL_CREATE_TABLE)
db.execSQL(UserSchema.UserAddressSchema.SQL_CREATE_TABLE)
db.execSQL(InteractionSchema.SQL_CREATE_TABLE)
db.execSQL(InAppInteractionSchema.SQL_CREATE_TABLE)
db.execSQL(EventsSchema.SQL_CREATE_TABLE)
db.execSQL(EventsSchema.EventSchema.SQL_CREATE_TABLE)
db.execSQL(AppInboxSchema.SQL_CREATE_TABLE)
db.execSQL(RecomEventsSchema.SQL_CREATE_TABLE)
db.execSQL(RecomEventsSchema.RecomEventSchema.SQL_CREATE_TABLE)
db.execSQL(WrappedLinkSchema.SQL_CREATE_TABLE)
db.execSQL(LogEventSchema.SQL_CREATE_TABLE)
db.execSQL(InAppMessageSchema.SQL_CREATE_TABLE)
db.execSQL(InAppMessageSchema.SegmentSchema.SQL_CREATE_TABLE)
}

override fun query(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ internal class RetenoDatabaseManagerImpl(
private val appInboxManager: RetenoDatabaseManagerAppInbox,
private val recomEventsManager: RetenoDatabaseManagerRecomEvents,
private val wrappedLinkManager: RetenoDatabaseManagerWrappedLink,
private val logEventManager: RetenoDatabaseManagerLogEvent
private val logEventManager: RetenoDatabaseManagerLogEvent,
private val inAppMessagesManager: RetenoDatabaseManagerInAppMessages,
private val inAppInteractionManager: RetenoDatabaseManagerInAppInteraction
): RetenoDatabaseManager {

override fun isDatabaseEmpty(): Boolean {
Expand All @@ -22,6 +24,8 @@ internal class RetenoDatabaseManagerImpl(
val recomEventsCount = recomEventsManager.getRecomEventsCount()
val wrappedLinksCount = wrappedLinkManager.getWrappedLinksCount()
val logEventsCount = logEventManager.getLogEventsCount()
val inAppMessagesCount = inAppMessagesManager.getInAppMessagesCount()
val inAppInteractionsCount = inAppInteractionManager.getInAppInteractionsCount()

val result = deviceCount == 0L
&& userCount == 0L
Expand All @@ -31,6 +35,8 @@ internal class RetenoDatabaseManagerImpl(
&& recomEventsCount == 0L
&& wrappedLinksCount == 0L
&& logEventsCount == 0L
&& inAppMessagesCount == 0L
&& inAppInteractionsCount == 0L
/*@formatter:off*/ Logger.i(TAG, "isDatabaseEmpty(): ", "result = $result")
/*@formatter:on*/
return result
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.reteno.core.data.local.database.manager

import com.reteno.core.data.local.model.interaction.InAppInteractionDb

interface RetenoDatabaseManagerInAppInteraction {
fun insertInteraction(interaction: InAppInteractionDb)
fun getInteractions(limit: Int? = null): List<InAppInteractionDb>
fun getInAppInteractionsCount(): Long
fun deleteInteraction(interaction: InAppInteractionDb): Boolean
fun deleteInteractionsByTime(outdatedTime: String): List<InAppInteractionDb>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package com.reteno.core.data.local.database.manager

import android.content.ContentValues
import android.database.Cursor
import android.database.SQLException
import androidx.core.database.getLongOrNull
import androidx.core.database.getStringOrNull
import com.reteno.core.data.local.database.RetenoDatabase
import com.reteno.core.data.local.database.schema.DbSchema
import com.reteno.core.data.local.database.schema.InAppInteractionSchema
import com.reteno.core.data.local.database.util.getInAppInteraction
import com.reteno.core.data.local.database.util.putInAppInteraction
import com.reteno.core.data.local.model.interaction.InAppInteractionDb
import com.reteno.core.util.Logger

internal class RetenoDatabaseManagerInAppInteractionImpl(
private val database: RetenoDatabase
) : RetenoDatabaseManagerInAppInteraction {

private val contentValues = ContentValues()

override fun insertInteraction(interaction: InAppInteractionDb) {
/*@formatter:off*/ Logger.i(TAG, "insertInteraction(): ", "inAppInteraction = [", interaction, "]")
/*@formatter:on*/
contentValues.putInAppInteraction(interaction)
database.insert(table = InAppInteractionSchema.TABLE_NAME_IN_APP_INTERACTION, contentValues = contentValues)
contentValues.clear()
}

override fun getInteractions(limit: Int?): List<InAppInteractionDb> {
/*@formatter:off*/ Logger.i(TAG, "getInAppInteractions(): ", "limit = [", limit, "]")
/*@formatter:on*/

val interactions: MutableList<InAppInteractionDb> = mutableListOf()

var cursor: Cursor? = null
try {
cursor = database.query(
table = InAppInteractionSchema.TABLE_NAME_IN_APP_INTERACTION,
columns = InAppInteractionSchema.getAllColumns(),
orderBy = "${DbSchema.COLUMN_TIMESTAMP} ASC",
limit = limit?.toString()
)
while (cursor.moveToNext()) {
val timestamp = cursor.getStringOrNull(cursor.getColumnIndex(DbSchema.COLUMN_TIMESTAMP))
val interaction = cursor.getInAppInteraction()

if (interaction != null) {
interactions.add(interaction)
} else {
val rowId =
cursor.getLongOrNull(cursor.getColumnIndex(InAppInteractionSchema.COLUMN_IN_APP_INTERACTION_ROW_ID))
val exception =
SQLException("Unable to read data from SQL database. timeStamp=$timestamp, interaction=$interaction")
if (rowId == null) {
/*@formatter:off*/ Logger.e(TAG, "getInteractions(). rowId is NULL ", exception)
/*@formatter:on*/
} else {
database.delete(
table = InAppInteractionSchema.TABLE_NAME_IN_APP_INTERACTION,
whereClause = "${InAppInteractionSchema.COLUMN_IN_APP_INTERACTION_ROW_ID}=?",
whereArgs = arrayOf(rowId.toString())
)
/*@formatter:off*/ Logger.e(TAG, "getInteractions(). Removed invalid entry from database. interaction=$interaction ", exception)
/*@formatter:on*/
}
}
}
} catch (t: Throwable) {
/*@formatter:off*/ Logger.e(TAG, "handleSQLiteError(): Unable to get Interactions from the table", t)
/*@formatter:on*/
} finally {
cursor?.close()
}
return interactions
}

override fun getInAppInteractionsCount(): Long = database.getRowCount(InAppInteractionSchema.TABLE_NAME_IN_APP_INTERACTION)

override fun deleteInteraction(interaction: InAppInteractionDb): Boolean {
/*@formatter:off*/ Logger.i(TAG, "deleteInteraction(): ", "interaction = [", interaction, "]")
/*@formatter:on*/

val removedRecordsCount = database.delete(
table = InAppInteractionSchema.TABLE_NAME_IN_APP_INTERACTION,
whereClause = "${InAppInteractionSchema.COLUMN_IN_APP_INTERACTION_ROW_ID}=?",
whereArgs = arrayOf(interaction.rowId)
)

return removedRecordsCount > 0
}

override fun deleteInteractionsByTime(outdatedTime: String): List<InAppInteractionDb> {
/*@formatter:off*/ Logger.i(TAG, "deleteInteractionByTime(): ", "outdatedTime = [", outdatedTime, "]")
/*@formatter:on*/

val whereClause = "${InAppInteractionSchema.COLUMN_IN_APP_INTERACTION_TIME} < '$outdatedTime'"

var cursor: Cursor? = null
val interactionsList = mutableListOf<InAppInteractionDb>()
try {
cursor = database.query(
table = InAppInteractionSchema.TABLE_NAME_IN_APP_INTERACTION,
columns = InAppInteractionSchema.getAllColumns(),
selection = whereClause
)

while (cursor.moveToNext()) {
val interaction = cursor.getInAppInteraction()
if (interaction != null) {
interactionsList.add(interaction)
} else {
val rowId = cursor.getLongOrNull(
cursor.getColumnIndex(InAppInteractionSchema.COLUMN_IN_APP_INTERACTION_ROW_ID)
)
val exception =
SQLException("deleteInteractionByTime() Unable to read data from SQL database. interaction=$interaction")
if (rowId == null) {
/*@formatter:off*/ Logger.e(TAG, "deleteInteractionByTime(). rowId is NULL ", exception)
/*@formatter:on*/
} else {
database.delete(
table = InAppInteractionSchema.TABLE_NAME_IN_APP_INTERACTION,
whereClause = "${InAppInteractionSchema.COLUMN_IN_APP_INTERACTION_ROW_ID}=?",
whereArgs = arrayOf(rowId.toString())
)
/*@formatter:off*/ Logger.e(TAG, "deleteInteractionByTime(). Removed invalid entry from database. interaction=$interaction ", exception)
/*@formatter:on*/
}
}
}
} catch (t: Throwable) {
/*@formatter:off*/ Logger.e(TAG, "deleteInteractionByTime() handleSQLiteError(): Unable to get Interactions from the table.", t)
/*@formatter:on*/
} finally {
cursor?.close()
}

database.delete(
table = InAppInteractionSchema.TABLE_NAME_IN_APP_INTERACTION,
whereClause = whereClause
)

return interactionsList
}

companion object {
private val TAG: String = RetenoDatabaseManagerInAppInteractionImpl::class.java.simpleName
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.reteno.core.data.local.database.manager

import com.reteno.core.data.local.model.iam.InAppMessageDb

interface RetenoDatabaseManagerInAppMessages {
fun insertInAppMessages(inApps: List<InAppMessageDb>)
fun getInAppMessages(limit: Int? = null): List<InAppMessageDb>
fun getInAppMessagesCount(): Long
fun deleteInAppMessages(inApps: List<InAppMessageDb>)
fun deleteAllInAppMessages()
}

0 comments on commit ef9bfc3

Please sign in to comment.