Skip to content

Commit

Permalink
Merge pull request #664 from Iterable/evan/feature/placement-support
Browse files Browse the repository at this point in the history
Evan/feature/placement support
  • Loading branch information
evantk91 authored Dec 12, 2023
2 parents a954139 + 101a6c7 commit ee7a42d
Show file tree
Hide file tree
Showing 12 changed files with 649 additions and 74 deletions.
1 change: 1 addition & 0 deletions iterableapi/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ dependencies {
testImplementation 'org.khronos:opengl-api:gl1.1-android-2.1_r1'
testImplementation 'com.squareup.okhttp3:mockwebserver:4.2.2'
testImplementation 'org.skyscreamer:jsonassert:1.5.0'
testImplementation project(':iterableapi')

androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test:rules:1.3.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,25 +241,58 @@ void getInAppMessages(int count, @NonNull IterableHelper.IterableActionHandler o
}

/**
* A package-private method to get a list of Embedded Messages from Iterable;
* Passes the result to the callback.
* To get list of messages as a list of EmbeddedMessages in memory, use
* {@link IterableEmbeddedManager#getEmbeddedMessages()} instead
* Gets a list of placements for the list of placement ids passed in from Iterable and
* passes the result to the callback;
* To get list of messages as a list of Embedded Messages in memory, use
* {@link IterableEmbeddedManager#getMessages(long)} instead.
* If no placement ids are passed in, all available messages with corresponding placement id will be returned
*
* @param placementIds array of placement ids - optional
* @param onCallback
*/
void getEmbeddedMessages(@NonNull IterableHelper.IterableActionHandler onCallback) {

public void getEmbeddedMessages(@Nullable Long[] placementIds, @NonNull IterableHelper.IterableActionHandler onCallback) {
if (!checkSDKInitialization()) {
return;
}
apiClient.getEmbeddedMessages(placementIds, onCallback);
}

/**
* Gets a list of placements for the list of placement ids passed in from Iterable and
* passes the result to the success or failure callback;
* To get list of messages as a list of Embedded Messages in memory, use
* {@link IterableEmbeddedManager#getMessages(long)} instead.
* If no placement ids are passed in, all available messages with corresponding placement id will be returned
*
* @param placementIds array of placement ids - optional
* @param onSuccess
* @param onFailure
*/

public void getEmbeddedMessages(@Nullable Long[] placementIds, @NonNull IterableHelper.SuccessHandler onSuccess, @NonNull IterableHelper.FailureHandler onFailure) {
if (!checkSDKInitialization()) {
return;
}
apiClient.getEmbeddedMessages(onCallback);
apiClient.getEmbeddedMessages(placementIds, onSuccess, onFailure);
}

/**
* A package-private method to get a list of Embedded Messages from Iterable;
* Passes the result to the success or failure callback.
* Used by the IterableEmbeddedManager.
*
* To get list of messages as a list of EmbeddedMessages in memory, use
* {@link IterableEmbeddedManager#getMessages(long)} instead
*
* @param onSuccess
* @param onFailure
*/
void getEmbeddedMessages(@NonNull IterableHelper.SuccessHandler onSuccess, @NonNull IterableHelper.FailureHandler onFailure) {
if (!checkSDKInitialization()) {
return;
}
apiClient.getEmbeddedMessages(onSuccess, onFailure);
apiClient.getEmbeddedMessages(null, onSuccess, onFailure);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public void getInAppMessages(int count, @NonNull IterableHelper.IterableActionHa
}
}

void getEmbeddedMessages(@NonNull IterableHelper.IterableActionHandler onCallback) {
void getEmbeddedMessages(@Nullable Long[] placementIds, @NonNull IterableHelper.IterableActionHandler onCallback) {
JSONObject requestJSON = new JSONObject();

try {
Expand All @@ -226,15 +226,26 @@ void getEmbeddedMessages(@NonNull IterableHelper.IterableActionHandler onCallbac
requestJSON.put(IterableConstants.ITBL_KEY_SDK_VERSION, IterableConstants.ITBL_KEY_SDK_VERSION_NUMBER);
requestJSON.put(IterableConstants.ITBL_SYSTEM_VERSION, Build.VERSION.RELEASE);
requestJSON.put(IterableConstants.KEY_PACKAGE_NAME, authProvider.getContext().getPackageName());
requestJSON.put("placementId", "0");

sendGetRequest(IterableConstants.ENDPOINT_GET_EMBEDDED_MESSAGES, requestJSON, onCallback);
if (placementIds != null) {
StringBuilder pathBuilder = new StringBuilder(IterableConstants.ENDPOINT_GET_EMBEDDED_MESSAGES + "?");

for (Long placementId : placementIds) {
pathBuilder.append("&placementIds=").append(placementId);
}

String path = pathBuilder.toString();
sendGetRequest(path, requestJSON, onCallback);
} else {
sendGetRequest(IterableConstants.ENDPOINT_GET_EMBEDDED_MESSAGES, requestJSON, onCallback);
}

} catch (JSONException e) {
e.printStackTrace();
}
}

void getEmbeddedMessages(@NonNull IterableHelper.SuccessHandler onSuccess, @NonNull IterableHelper.FailureHandler onFailure) {
void getEmbeddedMessages(@Nullable Long[] placementIds, @NonNull IterableHelper.SuccessHandler onSuccess, @NonNull IterableHelper.FailureHandler onFailure) {
JSONObject requestJSON = new JSONObject();

try {
Expand All @@ -243,9 +254,20 @@ void getEmbeddedMessages(@NonNull IterableHelper.SuccessHandler onSuccess, @NonN
requestJSON.put(IterableConstants.ITBL_KEY_SDK_VERSION, IterableConstants.ITBL_KEY_SDK_VERSION_NUMBER);
requestJSON.put(IterableConstants.ITBL_SYSTEM_VERSION, Build.VERSION.RELEASE);
requestJSON.put(IterableConstants.KEY_PACKAGE_NAME, authProvider.getContext().getPackageName());
requestJSON.put("placementId", "0");

sendGetRequest(IterableConstants.ENDPOINT_GET_EMBEDDED_MESSAGES, requestJSON, onSuccess, onFailure);
if (placementIds != null) {
StringBuilder pathBuilder = new StringBuilder(IterableConstants.ENDPOINT_GET_EMBEDDED_MESSAGES + "?");

for (Long placementId : placementIds) {
pathBuilder.append("&placementIds=").append(placementId);
}

String path = pathBuilder.toString();
sendGetRequest(path, requestJSON, onSuccess, onFailure);
} else {
sendGetRequest(IterableConstants.ENDPOINT_GET_EMBEDDED_MESSAGES, requestJSON, onSuccess, onFailure);
}

} catch (JSONException e) {
e.printStackTrace();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ public class IterableEmbeddedManager : IterableActivityMonitor.AppStateCallback
// endregion

// region variables
private var localMessages: List<IterableEmbeddedMessage> = ArrayList()
private var localPlacementMessagesMap = mutableMapOf<Long, List<IterableEmbeddedMessage>>()
private var placementIds = mutableListOf<Long>()

private var updateHandleListeners = mutableListOf<IterableEmbeddedUpdateHandler>()
private var iterableApi: IterableApi
private var context: Context
Expand Down Expand Up @@ -64,13 +66,16 @@ public class IterableEmbeddedManager : IterableActivityMonitor.AppStateCallback
// region public methods

//Gets the list of embedded messages in memory without syncing
fun getMessages(): List<IterableEmbeddedMessage> {
return localMessages
fun getMessages(placementId: Long): List<IterableEmbeddedMessage>? {
return localPlacementMessagesMap[placementId]
}

fun reset() {
val emptyMessages = listOf<IterableEmbeddedMessage>()
updateLocalMessages(emptyMessages)
localPlacementMessagesMap = mutableMapOf()
}

fun getPlacementIds(): List<Long> {
return placementIds
}

//Network call to get the embedded messages
Expand All @@ -80,26 +85,51 @@ public class IterableEmbeddedManager : IterableActivityMonitor.AppStateCallback
IterableApi.sharedInstance.getEmbeddedMessages(SuccessHandler { data ->
IterableLogger.v(TAG, "Got response from network call to get embedded messages")
try {
val remoteMessageList: MutableList<IterableEmbeddedMessage> = ArrayList()
val previousPlacementIds = getPlacementIds()
val currentPlacementIds: MutableList<Long> = mutableListOf()

val placementsArray = data.optJSONArray(IterableConstants.ITERABLE_EMBEDDED_MESSAGE_PLACEMENTS)
if (placementsArray != null) {
//if there are no placements in the payload
//reset the local message storage and trigger a UI update
if(placementsArray.length() == 0) {
reset()
if(previousPlacementIds.isNotEmpty()) {
updateHandleListeners.forEach {
IterableLogger.d(TAG, "Calling updateHandler")
it.onMessagesUpdated()
}
}
} else {
for (i in 0 until placementsArray.length()) {
val placementJson = placementsArray.optJSONObject(i)
val placement = IterableEmbeddedPlacement.fromJSONObject(placementJson)
val placementId = placement.placementId
val messages = placement.messages

currentPlacementIds.add(placementId)
updateLocalMessageMap(placementId, messages)
}
}
}

val placementArray = data.optJSONArray(IterableConstants.ITERABLE_EMBEDDED_MESSAGE_PLACEMENTS)
val placement = placementArray?.getJSONObject(0)
val messagesArray = placement?.optJSONArray(IterableConstants.ITERABLE_EMBEDDED_MESSAGE)
// compare previous placements to the current placement payload
val removedPlacementIds = previousPlacementIds.subtract(currentPlacementIds.toSet())

if (messagesArray != null) {
for (i in 0 until messagesArray.length()) {
val messageJson = messagesArray.optJSONObject(i)
val message = IterableEmbeddedMessage.fromJSONObject(messageJson)
remoteMessageList.add(message)
//if there are placements removed, update the local storage and trigger UI update
if(removedPlacementIds.isNotEmpty()) {
removedPlacementIds.forEach {
localPlacementMessagesMap.remove(it)
}

updateHandleListeners.forEach {
IterableLogger.d(TAG, "Calling updateHandler")
it.onMessagesUpdated()
}
} else {
IterableLogger.e(
TAG,
"Array not found in embedded message response. Probably a parsing failure"
)
}
updateLocalMessages(remoteMessageList)
IterableLogger.v(TAG, "$localMessages")

//store placements from payload for next comparison
placementIds = currentPlacementIds

} catch (e: JSONException) {
IterableLogger.e(TAG, e.toString())
Expand Down Expand Up @@ -157,45 +187,45 @@ public class IterableEmbeddedManager : IterableActivityMonitor.AppStateCallback
}
}

private fun updateLocalMessages(remoteMessageList: List<IterableEmbeddedMessage>) {
private fun updateLocalMessageMap(
placementId: Long,
remoteMessageList: List<IterableEmbeddedMessage>
) {
IterableLogger.printInfo()
var localMessagesChanged = false

// Get local messages in a mutable list
val localMessageList = getMessages().toMutableList()
val localMessageMap = mutableMapOf<String, IterableEmbeddedMessage>()
localMessageList.forEach {
getMessages(placementId)?.toMutableList()?.forEach {
localMessageMap[it.metadata.messageId] = it
}

// Check for new messages and add them to the local list
// Compare the remote list to local list
// if there are new messages, trigger a message update in UI and send out received events
remoteMessageList.forEach {
if (!localMessageMap.containsKey(it.metadata.messageId)) {
localMessagesChanged = true
localMessageList.add(it)
IterableApi.getInstance().trackEmbeddedMessageReceived(it)
}
}

// Check for messages in the local list that are not in the remote list and remove them
// Compare the local list to remote list
// if there are messages to remove, trigger a message update in UI
val remoteMessageMap = mutableMapOf<String, IterableEmbeddedMessage>()
remoteMessageList.forEach {
remoteMessageMap[it.metadata.messageId] = it
}
val messagesToRemove = mutableListOf<IterableEmbeddedMessage>()
localMessageList.forEach {
if (!remoteMessageMap.containsKey(it.metadata.messageId)) {
messagesToRemove.add(it)

//TODO: Make a call to the updateHandler to notify that the message has been removed
//TODO: Make a call to backend if needed
localPlacementMessagesMap[placementId]?.forEach {
if (!remoteMessageMap.containsKey(it.metadata.messageId)) {
localMessagesChanged = true
}
}
localMessageList.removeAll(messagesToRemove)

this.localMessages = localMessageList
// update local message map for placement with remote message list
localPlacementMessagesMap[placementId] = remoteMessageList

//if local messages changed, trigger a message update in UI
if (localMessagesChanged) {
updateHandleListeners.forEach {
IterableLogger.d(TAG, "Calling updateHandler")
Expand Down
Loading

0 comments on commit ee7a42d

Please sign in to comment.