Skip to content

Commit

Permalink
Initialize the framework first and Create a queue for the tag events
Browse files Browse the repository at this point in the history
With this change, the library will be initialized but it will wait for the panelist internet app to respond and give us the panelist cookies. Then updates the cookies and the send tag events will be sent with the new cookie.
  • Loading branch information
Morteza-Rastgoo committed Sep 3, 2021
1 parent 2be50eb commit a611025
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal class TSMobileAnalyticsBackend : TSMobileAnalytics {
* Constructor used internally only.
* Use createInstance() and getInstance() instead.
*/
private constructor(context: Context, activity: ComponentActivity, cpId: String, applicationName: String, cookies: List<HttpCookie>, trackPanelistOnly: Boolean) : super() {
private constructor(context: Context, activity: ComponentActivity, cpId: String, applicationName: String, cookies: List<HttpCookie>?, trackPanelistOnly: Boolean) : super() {
dataRequestHandler = TagDataRequestHandler(context, activity, cpId, applicationName, cookies, trackPanelistOnly)
}

Expand All @@ -49,67 +49,49 @@ internal class TSMobileAnalyticsBackend : TSMobileAnalytics {
val cookieValue = "trackPanelistOnly=$onlyPanelist&isWebViewBased=$isWebBased&sdkVersion=$version"
val metaCookie = CookieHandler.createHttpCookie(TagStringsAndValues.SIFO_META_COOKIE_NAME, cookieValue)
CookieHandler.setupPanelistCookies(listOf(metaCookie))

if (frameworkInstance == null) {
if (paramsAreValid(cpID, applicationName)) {
if (paramsAreValid(cpID, applicationName)) {
if (frameworkInstance == null) {
CoroutineScope(Dispatchers.IO).launch {
TSMConfigUtil.syncConfig(activity,applicationName ?: "")
TSMConfigUtil.syncConfig(activity, applicationName ?: "")
}

initTags(activity, cpID!!, applicationName!!, onlyPanelist)

PanelistHandler.syncCookies(activity, activity) {
val requestHandled = initTags(activity, cpID!!, applicationName!!, onlyPanelist)
if (!requestHandled) {
initLegacyTags(activity, cpID, applicationName, onlyPanelist)
}
refreshCookiesAndKeys(activity,onlyPanelist)
frameworkInstance!!.dataRequestHandler.setStateReady()
}
}
} else {
logMessage("Mobile Application Tagging Framework already initialized")
logMessage("Refreshing panelist keys")
val cookies = PanelistHandler.getCookies(activity, activity)
if (cookies != null) {
frameworkInstance!!.dataRequestHandler.refreshCookies(activity, cookies)
} else {
frameworkInstance!!.dataRequestHandler.refreshCookies(activity, PanelistHandler.getPanelistKey(activity))
log("Mobile Application Tagging Framework already initialized")
refreshCookiesAndKeys(activity, onlyPanelist)
}
}
return frameworkInstance
}

/**
* Print text to LogCat following a specific pattern and the tag "MobileAppTagging".
*
* @param message The message to print.
*/
fun logMessage(message: String) {
if (logPrintsActivated) {
Log.i("MobileAppTagging", message)
Log.i("MobileAppTagging", "***********************************")
}
}

/**
* Print an error message to LogCat following a specific pattern and the tag "MobileAppTagging"
* only if logs are activated.
*
* @param message The error message.
*/
fun logError(message: String) {
if (logPrintsActivated) {
Log.e("MobileAppTagging", "***********************************")
Log.e("MobileAppTagging", message)
Log.e("MobileAppTagging", "***********************************")
private fun refreshCookiesAndKeys(activity: ComponentActivity, onlyPanelist: Boolean) {
val isInstalled = activity.isPackageInstalled(TagStringsAndValues.SIFO_PANELIST_PACKAGE_NAME_V2)
if (!isInstalled) {
//TODO: 2021-09-02 Do we need logFatalError when onlyPanelist ==true?
//No need to refresh the cookies since there is no panelist app to get the cookies from
return
}
log("Refreshing panelist keys(Cookies)")
val cookies = PanelistHandler.getCookies(activity, activity)
frameworkInstance!!.dataRequestHandler.apply {
if (cookies != null) {
refreshCookies(cookies)
} else {
val panelistKey = PanelistHandler.getPanelistKey(activity)
if (onlyPanelist && panelistKey == TagStringsAndValues.NO_PANELIST_ID) {
fatalError("Mobile Application Tagging Framework Failed to initiate - " +
"Panelist Id was not found, it must exist if only panelist tracking is active")
return
}
refreshCookies(panelistKey)
}
}
}

/**
* Print an error message to LogCat following a specific pattern and the tag "MobileAppTagging".
*
* @param message The error message.
*/
fun logFatalError(message: String) {
Log.e("MobileAppTagging", "***********************************")
Log.e("MobileAppTagging", message)
Log.e("MobileAppTagging", "***********************************")
}

private fun paramsAreValid(cpID: String?, applicationName: String?): Boolean {
Expand All @@ -136,35 +118,14 @@ internal class TSMobileAnalyticsBackend : TSMobileAnalytics {
}
}


private fun initTags(activity: ComponentActivity, cpID: String, applicationName: String, onlyPanelist: Boolean): Boolean {
val cookies = PanelistHandler.getCookies(activity, activity) ?: return false
if (onlyPanelist && cookies.isEmpty()) {
logFatalError("Mobile Application Tagging Framework Failed to initiate - " +
"Cookies file was empty, panelist id not found")
} else {
frameworkInstance = TSMobileAnalyticsBackend(activity, activity, cpID, applicationName, cookies, onlyPanelist)
logMessage("Mobile Application Tagging Framework initiated with the following values " +
frameworkInstance = TSMobileAnalyticsBackend(activity, activity, cpID, applicationName, null, onlyPanelist)
log("Mobile Application Tagging Framework initiated with the following values " +
"\nCPID: $cpID\nApplication name: $applicationName\nOnly panelist tracking : $onlyPanelist")
}
return true
}

private fun initLegacyTags(activity: ComponentActivity, cpID: String, applicationName: String, onlyPanelist: Boolean) {
val panelistKey = PanelistHandler.getPanelistKey(activity)
if (cpID.length != TagStringsAndValues.CPID_LENGTH_CODIGO) {
fatalError("Mobile Application Tagging Framework Failed to initiate - " +
"CPID must either be exactly " + TagStringsAndValues.CPID_LENGTH_CODIGO)
} else if (onlyPanelist && panelistKey == TagStringsAndValues.NO_PANELIST_ID) {
fatalError("Mobile Application Tagging Framework Failed to initiate - " +
"Panelist Id was not found, it must exist if only panelist tracking is active")
} else {
// TODO print panelist setting
frameworkInstance = TSMobileAnalyticsBackend(activity, activity, cpID, applicationName, panelistKey, onlyPanelist)
log("Mobile Application Tagging Framework initiated with the following values " +
"\nCPID: $cpID\nApplication name: $applicationName\nOnly panelist tracking : $onlyPanelist")
}
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import java.util.concurrent.Executors
*/
internal class TagDataRequestHandler : TagDataRequestCallbackListener {

var state = PREPARING

/**
* Counter keeping track of the number of successful requests.
*/
Expand Down Expand Up @@ -71,7 +73,14 @@ internal class TagDataRequestHandler : TagDataRequestCallbackListener {
* @param applicationName The name of the application.
* @param cookies The list of cookies to send with measurement requests.
*/
constructor(context: Context, activity: ComponentActivity, cpId: String, applicationName: String, cookies: List<HttpCookie>, trackPanelistOnly: Boolean) {
constructor(
context: Context,
activity: ComponentActivity,
cpId: String,
applicationName: String,
cookies: List<HttpCookie>?,
trackPanelistOnly: Boolean
) {
tagHandler = TagHandler(context, cpId, applicationName, cookies)
dataRequestQueue = ArrayList()
activityForPref = activity
Expand All @@ -87,20 +96,27 @@ internal class TagDataRequestHandler : TagDataRequestCallbackListener {
* @param applicationName The name of the application.
* @param panelistKey The panelist key.
*/
constructor(context: Context, activity: ComponentActivity,cpId: String, applicationName: String, panelistKey: String, trackPanelistOnly: Boolean) {
constructor(
context: Context,
activity: ComponentActivity,
cpId: String,
applicationName: String,
panelistKey: String,
trackPanelistOnly: Boolean
) {
tagHandler = TagHandler(context, cpId, applicationName, panelistKey)
dataRequestQueue = ArrayList()
activityForPref = activity
threadPool = Executors.newScheduledThreadPool(MAX_NBR_OF_THREADS)
this.trackPanelistOnly = trackPanelistOnly
}

fun refreshCookies(context: Context, cookies: List<HttpCookie>) {
tagHandler.refresh(context, cookies)
fun refreshCookies(cookies: List<HttpCookie>) {
tagHandler.refresh(cookies)
}

fun refreshCookies(context: Context, panelistKey: String) {
tagHandler.refresh(context, panelistKey)
fun refreshCookies(panelistKey: String) {
tagHandler.refresh(panelistKey)
}

/**
Expand All @@ -115,23 +131,44 @@ internal class TagDataRequestHandler : TagDataRequestCallbackListener {
val result = checkRequestParams(category, contentID)
if (result == TagStringsAndValues.RESULT_SUCCESS) {
val request = TagDataRequest(
category!!,
contentID!!,
getURL(category, contentID),
trackPanelistOnly,
tagHandler.applicationName,
tagHandler.applicationVersion,
this,
userCallbackListener
category!!,
contentID!!,
getURL(category, contentID),
trackPanelistOnly,
tagHandler.applicationName,
tagHandler.applicationVersion,
this,
userCallbackListener
)
synchronized(this) {
dataRequestQueue.add(request)
runRequest(request)
}
log( "Request added to the queue")
dataRequestQueue.add(request)
runRequestQueue()
}
return result
}

fun setStateReady() {
log( "Lib is ready for logging...")
state = READY
runRequestQueue()
}

/**
* Runs the request queue to send all queued tags
*/
private fun runRequestQueue() {
if (state == READY) {
if (dataRequestQueue.isNotEmpty()) {
runRequestQueueThread()
} else {
log( "Request queue is empty. Skip it...")
}
} else {
// Wait for the READY state...
log( "Waiting for the library to get ready...")
}
}

/**
* Send a tag-request to the server.
*
Expand Down Expand Up @@ -227,23 +264,38 @@ internal class TagDataRequestHandler : TagDataRequestCallbackListener {
/**
* Init the server request to the specified URL in a new thread.
*/
private fun runRequest(request: TagDataRequest) {
val thread = RequestThread()
thread.request = request
threadPool.execute(thread)
private fun runRequestQueueThread() {
synchronized(dataRequestQueue) {
val thread = RequestThread()
thread.requests.addAll(dataRequestQueue)
dataRequestQueue.clear()
threadPool.execute(thread)
}
}

/**
* A thread to run the request to the server.
*/
private inner class RequestThread : Runnable {
var request: TagDataRequest? = null
var requests: MutableList<TagDataRequest> = mutableListOf()

override fun run() {
request?.initRequest()
log( "Request queue(${requests.size}): STARTED")
requests.forEach {
log( "Run request: " + it.cat)
it.initRequest()
}
log( "Queue cleared!")
}
}

/**
* Holds states of the handler
*/
enum class State {
PREPARING, READY,
}

companion object {
/**
* The maximum number of simultaneous request threads.
Expand Down
Loading

0 comments on commit a611025

Please sign in to comment.