Skip to content

Commit f1fb3b6

Browse files
feat: support modal background opacity through CustomJson (RMCCX-7327)
1 parent 4a4ffba commit f1fb3b6

File tree

13 files changed

+201
-19
lines changed

13 files changed

+201
-19
lines changed

dependency_check_suppressions.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<vulnerabilityName>CVE-2021-22569</vulnerabilityName>
3030
<vulnerabilityName>CVE-2022-3171</vulnerabilityName>
3131
<vulnerabilityName>CVE-2022-3509</vulnerabilityName>
32+
<vulnerabilityName>CVE-2024-7254</vulnerabilityName>
3233
</suppress>
3334
<suppress until="2024-12-31Z">
3435
<notes><![CDATA[
@@ -107,4 +108,20 @@
107108
<vulnerabilityName>CVE-2022-3171</vulnerabilityName>
108109
<vulnerabilityName>CVE-2022-3510</vulnerabilityName>
109110
</suppress>
111+
<suppress until="2024-12-31Z">
112+
<notes><![CDATA[
113+
file name: work-runtime-2.7.1.aar: inspector.jar (shaded: com.google.protobuf:protobuf-javalite:3.10.0)
114+
]]></notes>
115+
<packageUrl regex="true">^pkg:maven/com\.google\.protobuf/protobuf\-javalite@.*$</packageUrl>
116+
<vulnerabilityName>CVE-2024-7254</vulnerabilityName>
117+
</suppress>
118+
119+
<!-- Compose (Sample app) -->
120+
<suppress until="2024-12-31Z">
121+
<notes><![CDATA[
122+
file name: ui-1.2.0-rc02.aar: inspector.jar (shaded: com.google.protobuf:protobuf-javalite:3.19.4)
123+
]]></notes>
124+
<packageUrl regex="true">^pkg:maven/com\.google\.protobuf/protobuf\-javalite@.*$</packageUrl>
125+
<vulnerabilityName>CVE-2024-7254</vulnerabilityName>
126+
</suppress>
110127
</suppressions>

inappmessaging/USERGUIDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ All the events "launch the app event, login event, purchase successful event, cu
501501
- RMCCX-6876: Improved console logging.
502502
* RMC SDK updates:
503503
- RMCCX-7186: Supported Clickable Image through CustomJson.
504+
- RMCCX-7327: Supported customizable modal campaign background opacity through CustomJson.
504505

505506
#### 7.6.0 (2024-09-17)
506507
* Improvements:

inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/customjson/ApplyClickableImage.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,8 @@ internal fun UiMessage.applyCustomClickableImage(clickableImage: ClickableImage?
1919
return false
2020
}
2121

22-
return if (this.startsWith("http")) {
23-
Regex("https://.*").matches(this)
24-
} else {
25-
Regex(".*://.*").matches(this)
26-
}
22+
val allowedPattern = Regex("https://.*|.*://.*")
23+
return this.matches(allowedPattern)
2724
}
2825

2926
@SuppressWarnings("ComplexCondition")

inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/customjson/CustomJson.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.rakuten.tech.mobile.inappmessaging.runtime.data.customjson
33
internal data class CustomJson(
44
val pushPrimer: PushPrimer? = null,
55
val clickableImage: ClickableImage? = null,
6+
val background: Background? = null,
67
)
78

89
internal data class PushPrimer(
@@ -18,3 +19,13 @@ internal data class ClickableImage(
1819
*/
1920
val url: String? = null,
2021
)
22+
23+
/**
24+
* Backdrop color.
25+
*/
26+
internal data class Background(
27+
/**
28+
* Opacity from 0 (completely transparent) to 1 (completely opaque).
29+
*/
30+
val opacity: Float? = null,
31+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.rakuten.tech.mobile.inappmessaging.runtime.data.customjson
2+
3+
import com.google.gson.JsonDeserializationContext
4+
import com.google.gson.JsonDeserializer
5+
import com.google.gson.JsonElement
6+
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppLogger
7+
import java.lang.reflect.Type
8+
9+
internal class CustomJsonDeserializer : JsonDeserializer<CustomJson> {
10+
11+
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): CustomJson {
12+
val jsonObject = json?.asJsonObject
13+
14+
val pushPrimer = context?.safeDeserialize<PushPrimer>(jsonObject?.get("pushPrimer"))
15+
val clickableImage = context?.safeDeserialize<ClickableImage>(jsonObject?.get("clickableImage"))
16+
val background = context?.safeDeserialize<Background>(jsonObject?.get("background"))
17+
18+
return CustomJson(pushPrimer, clickableImage, background)
19+
}
20+
21+
@SuppressWarnings("TooGenericExceptionCaught")
22+
private inline fun <reified T> JsonDeserializationContext.safeDeserialize(jsonElement: JsonElement?): T? {
23+
return try {
24+
this.deserialize<T>(jsonElement, T::class.java)
25+
} catch (_: Exception) {
26+
InAppLogger("IAM_CustomJsonDeserializer")
27+
.warn("Invalid format for ${T::class.java.name.split(".").lastOrNull()}")
28+
null
29+
}
30+
}
31+
}

inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/customjson/MessageMapper.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import com.rakuten.tech.mobile.inappmessaging.runtime.data.ui.UiMessage
1313
internal object MessageMapper : Mapper<Message, UiMessage> {
1414

1515
override fun mapFrom(from: Message): UiMessage {
16+
val customJsonData = from.getCustomJsonData()
17+
1618
val uiModel = UiMessage(
1719
id = from.campaignId,
1820
type = from.type,
@@ -28,13 +30,13 @@ internal object MessageMapper : Mapper<Message, UiMessage> {
2830
displaySettings = from.messagePayload.messageSettings.displaySettings,
2931
content = from.messagePayload.messageSettings.controlSettings.content,
3032
tooltipData = from.getTooltipConfig(),
33+
backdropOpacity = customJsonData?.background?.opacity,
3134
)
3235

33-
// Apply CustomJson rules if exists
34-
val customJsonData = from.getCustomJsonData()
3536
return if (customJsonData == null) {
3637
uiModel
3738
} else {
39+
// Update any data that exists from main payload to CustomJson data if applicable
3840
uiModel
3941
.applyCustomPushPrimer(customJsonData.pushPrimer)
4042
.applyCustomClickableImage(customJsonData.clickableImage, from.isPushPrimer)

inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/responses/ping/Message.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.rakuten.tech.mobile.inappmessaging.runtime.data.responses.ping
22

33
import com.google.gson.Gson
4+
import com.google.gson.GsonBuilder
45
import com.google.gson.JsonObject
56
import com.google.gson.JsonParseException
67
import com.google.gson.annotations.SerializedName
78
import com.rakuten.tech.mobile.inappmessaging.runtime.RmcHelper
89
import com.rakuten.tech.mobile.inappmessaging.runtime.data.customjson.CustomJson
10+
import com.rakuten.tech.mobile.inappmessaging.runtime.data.customjson.CustomJsonDeserializer
911
import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.InAppMessageType
1012
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.Tooltip
1113
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppLogger
@@ -79,16 +81,19 @@ internal data class Message(
7981
return tooltip
8082
}
8183

84+
@SuppressWarnings("TooGenericExceptionCaught")
8285
fun getCustomJsonData(): CustomJson? {
8386
if (!RmcHelper.isRmcIntegrated() || customJson == null || customJson.entrySet().isEmpty()) {
8487
return null
8588
}
8689
if (customJsonData == null) {
8790
try {
88-
customJsonData = Gson().fromJson(customJson, CustomJson::class.java)
89-
} catch (je: JsonParseException) {
90-
InAppLogger(TAG).warn("getCustomJsonData - invalid customJson format")
91-
InAppLogger(TAG).debug("parse exception: $je")
91+
val gson = GsonBuilder()
92+
.registerTypeAdapter(CustomJson::class.java, CustomJsonDeserializer())
93+
.create()
94+
customJsonData = gson.fromJson(customJson, CustomJson::class.java)
95+
} catch (_: Exception) {
96+
InAppLogger(TAG).debug("getCustomJsonData - invalid customJson format")
9297
}
9398
}
9499
return customJsonData

inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/ui/UiMessage.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ internal data class UiMessage(
2323
val displaySettings: DisplaySettings,
2424
val content: Content?,
2525
val tooltipData: Tooltip?,
26+
val backdropOpacity: Float? = null,
2627
)

inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/view/InAppMessageModalView.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package com.rakuten.tech.mobile.inappmessaging.runtime.view
22

33
import android.content.Context
4+
import android.graphics.Color
45
import android.util.AttributeSet
56
import android.widget.LinearLayout
67
import androidx.annotation.VisibleForTesting
8+
import androidx.core.graphics.ColorUtils
79
import com.rakuten.tech.mobile.inappmessaging.runtime.R
810
import com.rakuten.tech.mobile.inappmessaging.runtime.data.ui.UiMessage
911

@@ -23,9 +25,26 @@ internal class InAppMessageModalView(
2325
super.populateViewData(uiMessage)
2426

2527
setCloseButton()
28+
setBackdropColor(uiMessage.backdropOpacity)
2629
findModalLayout()?.setBackgroundColor(bgColor)
2730
}
2831

2932
@VisibleForTesting
3033
fun findModalLayout(): LinearLayout? = findViewById(R.id.modal)
34+
35+
private fun setBackdropColor(opacity: Float?) {
36+
// The default color(R.color.in_app_message_frame_light) will be set through XML.
37+
if (opacity == null ||
38+
opacity !in 0f..1f
39+
) {
40+
return
41+
}
42+
43+
val blackWithAlpha = ColorUtils.setAlphaComponent(Color.BLACK, (opacity * MAX_COLOR_ALPHA).toInt())
44+
this.setBackgroundColor(blackWithAlpha)
45+
}
46+
47+
companion object {
48+
const val MAX_COLOR_ALPHA = 255
49+
}
3150
}

inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/customjson/ApplyClickableImageSpec.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class ApplyClickableImageSpec {
3131
uiMessage = message.applyCustomClickableImage(ClickableImage("ogle.124dsefsd"), false)
3232
uiMessage shouldBeEqualTo message
3333

34-
uiMessage = message.applyCustomClickableImage(ClickableImage("http://test.com"), false)
34+
uiMessage = message.applyCustomClickableImage(ClickableImage("intent:/invalid/deeplink"), false)
3535
uiMessage shouldBeEqualTo message
3636

3737
uiMessage = message.applyCustomClickableImage(ClickableImage(" myapp://open"), false)

0 commit comments

Comments
 (0)