Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MOB-22283] Exposing new API for generateDisplayXDM for batching multiple display propositions #3

Open
wants to merge 8 commits into
base: MOB-21475
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -2696,7 +2696,7 @@ public void testTrackPropositions_validPropositionInteractionsForDisplay_Multipl

// Action: Display both offers
TestHelper.resetTestExpectations();
Optimize.trackDisplayedPropositions(optimizePropositionList);
// Optimize.trackDisplayedPropositions(optimizePropositionList);

// Assert: Ensure Optimize and Edge events are dispatched correctly
List<Event> optimizeRequestEventsList =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

package com.adobe.marketing.mobile.optimize;

import static com.adobe.marketing.mobile.optimize.OfferExtension.toUniquePropositionsList;

import com.adobe.marketing.mobile.services.Log;
import com.adobe.marketing.mobile.util.DataReader;
import com.adobe.marketing.mobile.util.DataReaderException;
Expand Down Expand Up @@ -283,6 +285,17 @@ public void displayed() {
OptimizeUtils.trackWithData(generateDisplayInteractionXdm());
}

/**
* Dispatches an event for the Edge network extension to send an Experience Event to the Edge
* network with the display interaction data for the given {@code offer} list of offers.
*
* @param offers {@code List<Offer>} containing offer data.
* @see OptimizeUtils#trackWithData(Map)
*/
public static void displayed(List<Offer> offers) {
OptimizeUtils.trackWithData(generateDisplayInteractionXdm(offers));
}

/**
* Dispatches an event for the Edge network extension to send an Experience Event to the Edge
* network with the tap interaction data for the given {@code OptimizeProposition} offer.
Expand All @@ -304,16 +317,43 @@ public void tapped() {
* along with any additional XDM, free-form data, and override dataset identifier.
*
* @return {@code Map<String, Object>} containing the XDM data for the proposition interaction.
* @see OptimizeUtils#generateInteractionXdm(String, List, Boolean)
* @see OptimizeUtils#generateInteractionXdm(String, List)
*/
public Map<String, Object> generateDisplayInteractionXdm() {
if (propositionReference == null || propositionReference.get() == null) {
return null;
}
return OptimizeUtils.generateInteractionXdm(
OptimizeConstants.JsonValues.EE_EVENT_TYPE_PROPOSITION_DISPLAY,
Collections.singletonList(propositionReference.get()),
true);
Collections.singletonList(propositionReference.get()));
}

/**
* Generates a map containing XDM formatted data for {@code Experience Event -
* OptimizeProposition Interactions} field group from this {@code offer} list.
*
* <p>The returned XDM data does contain the {@code eventType} for the Experience Event with
* value {@code decisioning.propositionDisplay}.
*
* <p>Note: The Edge sendEvent API can be used to dispatch this data in an Experience Event
* along with any additional XDM, free-form data, and override dataset identifier.
*
* @param offers {@code List<Offer>} containing offer data.
* @return {@code Map<String, Object>} containing the XDM data for the proposition interaction.
* @see OptimizeUtils#generateInteractionXdm(String, List)
*/
public static Map<String, Object> generateDisplayInteractionXdm(List<Offer> offers) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Add @Nullable annotation to the API signature

List<OptimizeProposition> propositions = toUniquePropositionsList(offers);
if (propositions != null && !propositions.isEmpty()) {
return OptimizeUtils.generateInteractionXdm(
OptimizeConstants.JsonValues.EE_EVENT_TYPE_PROPOSITION_DISPLAY, propositions);
}
Log.debug(
OptimizeConstants.LOG_TAG,
SELF_TAG,
"Cannot generate XDM, provided list of offers belongs to null or empty"
+ " propositions");
return null;
}

/**
Expand All @@ -327,16 +367,15 @@ public Map<String, Object> generateDisplayInteractionXdm() {
* along with any additional XDM, free-form data, and override dataset identifier.
*
* @return {@code Map<String, Object>} containing the XDM data for the proposition interaction.
* @see OptimizeUtils#generateInteractionXdm(String, List, Boolean)
* @see OptimizeUtils#generateInteractionXdm(String, List)
*/
public Map<String, Object> generateTapInteractionXdm() {
if (propositionReference == null || propositionReference.get() == null) {
return null;
}
return OptimizeUtils.generateInteractionXdm(
OptimizeConstants.JsonValues.EE_EVENT_TYPE_PROPOSITION_INTERACT,
Collections.singletonList(propositionReference.get()),
true);
Collections.singletonList(propositionReference.get()));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
Copyright 2024 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/

package com.adobe.marketing.mobile.optimize

internal object OfferExtension {
@JvmStatic
fun List<Offer>?.toUniquePropositionsList(): List<OptimizeProposition>? {
Copy link

@spoorthipujariadobe spoorthipujariadobe Nov 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic here in conjunction with OptimizeUtils.generateInteractionXdm doesn't achieve our goal. You're creating a list of proposition reference for the list of offers passed in. Then in OptimizeUtils.generateInteractionXdm you're adding all the offer ids in the proposition to the display events, rather only the ids of offer list that was passed to the API.
https://github.com/siddique-adobe/aepsdk-optimize-android/pull/3/files#diff-b90c589ff2ce5c066bb12f60a6b2ce62e77b4fede59cbe980f944bd99f45680dR288

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please review this again, I've fixed the missing logic here @spoorthipujariadobe

if (this.isNullOrEmpty()) return null
val seenPropsIds = mutableSetOf<String>()
val offerIds = this.mapNotNull { it.id }.toSet()
return this
.mapNotNull { it.propositionReference?.get() }
.filter { proposition ->
with(proposition) {
id !in seenPropsIds && offers.any { it.id in offerIds }
}
}.onEach { proposition ->
seenPropsIds.add(proposition.id)
val filteredOffers = proposition.offers.filter { it.id in offerIds }
OptimizeProposition(
proposition.id,
filteredOffers,
proposition.scope,
proposition.scopeDetails
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -446,21 +446,4 @@ protected static void failWithOptimizeError(
callbackWithError.fail(error);
}
}

/**
* Dispatches an event for the Edge network extension to send an Experience Event to the Edge
* network with the display interaction data for the given {@code List<OptimizeProposition>}
* offer.
*
* @param propositions {@code List<OptimizeProposition>} containing the list of propositions
* @see OptimizeUtils#trackWithData(Map)
*/
public static void trackDisplayedPropositions(final List<OptimizeProposition> propositions) {
Map<String, Object> xdm =
OptimizeUtils.generateInteractionXdm(
OptimizeConstants.JsonValues.EE_EVENT_TYPE_PROPOSITION_DISPLAY,
propositions,
false);
OptimizeUtils.trackWithData(xdm);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,7 @@ static void trackWithData(final Map<String, Object> xdm) {
*/
protected static Map<String, Object> generateInteractionXdm(
final String experienceEventType,
final List<OptimizeProposition> pendingDisplayedPropositions,
final Boolean shouldAppendOfferIds) {
final List<OptimizeProposition> pendingDisplayedPropositions) {
List<Map<String, Object>> propositions = new ArrayList<>();
if (!pendingDisplayedPropositions.isEmpty()) {
for (OptimizeProposition prop : pendingDisplayedPropositions) {
Expand All @@ -261,7 +260,7 @@ protected static Map<String, Object> generateInteractionXdm(
OptimizeConstants.JsonKeys.DECISIONING_PROPOSITIONS_SCOPEDETAILS,
prop.getScopeDetails());

if (shouldAppendOfferIds && !prop.getOffers().isEmpty()) {
if (!prop.getOffers().isEmpty()) {
proposition.put(
OptimizeConstants.JsonKeys.DECISIONING_PROPOSITIONS_ITEMS,
getOfferIds(prop));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,27 @@ package com.adobe.marketing.optimizeapp

import android.view.ViewGroup
import android.webkit.WebView
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.absolutePadding
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
Expand All @@ -41,9 +56,8 @@ import com.adobe.marketing.mobile.edge.identity.IdentityItem
import com.adobe.marketing.mobile.edge.identity.IdentityMap
import com.adobe.marketing.mobile.optimize.DecisionScope
import com.adobe.marketing.mobile.optimize.Offer
import com.adobe.marketing.mobile.optimize.Offer.displayed
import com.adobe.marketing.mobile.optimize.OfferType
import com.adobe.marketing.mobile.optimize.Optimize.trackDisplayedPropositions
import com.adobe.marketing.mobile.optimize.OptimizeProposition
import com.adobe.marketing.optimizeapp.viewmodels.MainViewModel
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
Expand All @@ -57,8 +71,8 @@ private val displayHandler: (Offer) -> Unit = { offer ->
offer.displayed()
}

private val displayPropositionsHandler: (List<OptimizeProposition>) -> Unit = { props ->
trackDisplayedPropositions(props)
private val displayPropositionsHandler: (List<Offer>) -> Unit = { offers ->
displayed(offers)
}

@Composable
Expand Down