From aac3f57251a054df03206fe564f19b422d1ba144 Mon Sep 17 00:00:00 2001 From: PoornimaApptentive <85186738+PoornimaApptentive@users.noreply.github.com> Date: Wed, 20 Nov 2024 12:24:18 -0800 Subject: [PATCH] Release/6.9.1 (#37) Releasing 6.9.1 --- CHANGELOG.md | 7 ++++ .../feedback/ApptentiveDefaultClient.kt | 8 +++++ .../com/android/feedback/Constants.kt | 2 +- .../conversation/ConversationManager.kt | 17 ++++++++++ .../conversation/ConversationRepository.kt | 4 +++ .../com/android/feedback/model/Device.kt | 33 +++++++++++++++++++ .../conversation/ConversationManagerTest.kt | 15 ++++++++- .../resources/manifest_structure_test.json | 7 ++++ .../messagecenter/view/ProfileActivity.kt | 12 +++---- .../link/view/NavigateTolinkActivity.kt | 13 ++++++++ build.gradle | 2 +- 11 files changed, 111 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06d33292..c923e052 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# 2024-11-20 - v6.9.1 +### Fixes +* Device updates are now accurately captured in the conversation metadata. +* Support for Android 15's edge-to-edge feature implemented via Apptentive theme override. +* Updated WebView configuration settings to address a security vulnerability. +* Resolved the profile screen freezing issue. + # 2024-09-18 - v6.9.0 ### Fixes * Draft messages are now saved correctly in the multiuser environment diff --git a/apptentive-feedback/src/main/java/apptentive/com/android/feedback/ApptentiveDefaultClient.kt b/apptentive-feedback/src/main/java/apptentive/com/android/feedback/ApptentiveDefaultClient.kt index 1c6c85d1..ee7c3096 100644 --- a/apptentive-feedback/src/main/java/apptentive/com/android/feedback/ApptentiveDefaultClient.kt +++ b/apptentive-feedback/src/main/java/apptentive/com/android/feedback/ApptentiveDefaultClient.kt @@ -247,6 +247,14 @@ class ApptentiveDefaultClient( } } + conversationManager.deviceupdate.observe { deviceUpdated -> + if (deviceUpdated) { + val device = conversationManager.getConversation().device + val payload = device.toDevicePayload() + enqueuePayload(payload) + } + } + executors.main.execute { Log.i(LIFE_CYCLE_OBSERVER, "Observing App lifecycle") ProcessLifecycleOwner.get().lifecycle.addObserver( diff --git a/apptentive-feedback/src/main/java/apptentive/com/android/feedback/Constants.kt b/apptentive-feedback/src/main/java/apptentive/com/android/feedback/Constants.kt index a75681dc..4594b884 100644 --- a/apptentive-feedback/src/main/java/apptentive/com/android/feedback/Constants.kt +++ b/apptentive-feedback/src/main/java/apptentive/com/android/feedback/Constants.kt @@ -4,7 +4,7 @@ import apptentive.com.android.util.InternalUseOnly @InternalUseOnly object Constants { - const val SDK_VERSION = "6.9.0" + const val SDK_VERSION = "6.9.1" const val API_VERSION = 15 const val SERVER_URL = "https://api.apptentive.com" const val REDACTED_DATA = "" diff --git a/apptentive-feedback/src/main/java/apptentive/com/android/feedback/conversation/ConversationManager.kt b/apptentive-feedback/src/main/java/apptentive/com/android/feedback/conversation/ConversationManager.kt index 38817adf..6d698414 100644 --- a/apptentive-feedback/src/main/java/apptentive/com/android/feedback/conversation/ConversationManager.kt +++ b/apptentive-feedback/src/main/java/apptentive/com/android/feedback/conversation/ConversationManager.kt @@ -74,7 +74,11 @@ internal class ConversationManager( private val sdkAppReleaseUpdateSubject = BehaviorSubject(false) val sdkAppReleaseUpdate: Observable get() = sdkAppReleaseUpdateSubject + private val deviceUpdateSubject = BehaviorSubject(false) + val deviceupdate: Observable get() = deviceUpdateSubject + var isSDKAppReleaseCheckDone = false + var isDeviceUpdateCheckDone = false init { val conversation = loadActiveConversation() @@ -90,6 +94,7 @@ internal class ConversationManager( fun onEncryptionSetupComplete() { activeConversationSubject.observe(::saveConversation) activeConversation.observe(::checkForSDKAppReleaseUpdates) + activeConversation.observe(::checkForDeviceUpdates) } @RequiresApi(Build.VERSION_CODES.M) @@ -363,6 +368,18 @@ internal class ConversationManager( return conversationRepository.createConversation(conversationId, conversationToken) } + fun checkForDeviceUpdates(conversation: Conversation) { + if (isDeviceUpdateCheckDone) return else isDeviceUpdateCheckDone = true + Log.i(CONVERSATION, "Checking for device updates") + val currentDevice = conversationRepository.getCurrentDevice() + if (conversation.device != currentDevice) { + deviceUpdateSubject.value = true + Log.d(CONVERSATION, "Device updated: ${conversation.device} => $currentDevice") + // Keep the uuid same as the previous device conversation + updateDevice(currentDevice.copy(uuid = conversation.device.uuid)) + } + } + fun checkForSDKAppReleaseUpdates(conversation: Conversation) { // Check for SDK & AppRelease update once per session if (isSDKAppReleaseCheckDone) return else isSDKAppReleaseCheckDone = true diff --git a/apptentive-feedback/src/main/java/apptentive/com/android/feedback/conversation/ConversationRepository.kt b/apptentive-feedback/src/main/java/apptentive/com/android/feedback/conversation/ConversationRepository.kt index 3cb11e1c..e887cc7f 100644 --- a/apptentive-feedback/src/main/java/apptentive/com/android/feedback/conversation/ConversationRepository.kt +++ b/apptentive-feedback/src/main/java/apptentive/com/android/feedback/conversation/ConversationRepository.kt @@ -25,6 +25,8 @@ internal interface ConversationRepository { fun getCurrentAppRelease(): AppRelease + fun getCurrentDevice(): Device + fun getCurrentSdk(): SDK fun updateEncryption(encryption: Encryption) @@ -71,6 +73,8 @@ internal class DefaultConversationRepository( override fun getCurrentSdk(): SDK = sdkFactory.create() + override fun getCurrentDevice(): Device = deviceFactory.create() + override fun updateEncryption(encryption: Encryption) { conversationSerializer.setEncryption(encryption) } diff --git a/apptentive-feedback/src/main/java/apptentive/com/android/feedback/model/Device.kt b/apptentive-feedback/src/main/java/apptentive/com/android/feedback/model/Device.kt index 67feddd6..1eeda24a 100644 --- a/apptentive-feedback/src/main/java/apptentive/com/android/feedback/model/Device.kt +++ b/apptentive-feedback/src/main/java/apptentive/com/android/feedback/model/Device.kt @@ -63,4 +63,37 @@ data class Device( customData = customData.content, integrationConfig = integrationConfig.toPayload() ) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Device + + return !( + osName != other.osName || + osVersion != other.osVersion || + osBuild != other.osBuild || + osApiLevel != other.osApiLevel || + manufacturer != other.manufacturer || + model != other.model || + board != other.board || + product != other.product || + brand != other.brand || + cpu != other.cpu || + device != other.device || + buildType != other.buildType || + buildId != other.buildId || + carrier != other.carrier || + currentCarrier != other.currentCarrier || + networkType != other.networkType || + bootloaderVersion != other.bootloaderVersion || + radioVersion != other.radioVersion || + localeCountryCode != other.localeCountryCode || + localeLanguageCode != other.localeLanguageCode || + localeRaw != other.localeRaw || + customData != other.customData || + integrationConfig != other.integrationConfig + ) + } } diff --git a/apptentive-feedback/src/test/java/apptentive/com/android/feedback/conversation/ConversationManagerTest.kt b/apptentive-feedback/src/test/java/apptentive/com/android/feedback/conversation/ConversationManagerTest.kt index f42277d2..27714d54 100644 --- a/apptentive-feedback/src/test/java/apptentive/com/android/feedback/conversation/ConversationManagerTest.kt +++ b/apptentive-feedback/src/test/java/apptentive/com/android/feedback/conversation/ConversationManagerTest.kt @@ -124,7 +124,7 @@ class ConversationManagerTest : TestCase() { conversationManager.getConversation().device @Test - fun testDeviceUpdate() { + fun testCustomDataDeviceUpdate() { DefaultStateMachine.reset() DefaultStateMachine.onEvent(SDKEvent.RegisterSDK) DefaultStateMachine.onEvent(SDKEvent.ClientStarted) @@ -142,6 +142,17 @@ class ConversationManagerTest : TestCase() { assertEquals(updatedCustomData.content.size, getUpdatedDevice(conversationManager).customData.content.size) } + @Test + fun testNonCustomDataDeviceUpdate() { + DefaultStateMachine.reset() + DefaultStateMachine.onEvent(SDKEvent.RegisterSDK) + DefaultStateMachine.onEvent(SDKEvent.ClientStarted) + val conversationManager = createConversationManager() + // The mockConversationRepository updates the mockDevice with osApiLevel = 31, osVersion = "12" hence there is a device udpate + conversationManager.checkForDeviceUpdates(conversationManager.getConversation()) + assertTrue(conversationManager.isDeviceUpdateCheckDone) + } + @Test fun testAppReleaseSDKUpdate() { DefaultStateMachine.reset() @@ -270,6 +281,8 @@ class MockConversationRepository(val throwException: Boolean = false) : versionName = "Version name updated" ) + override fun getCurrentDevice(): Device = mockDevice.copy(osApiLevel = 31, osVersion = "12") + override fun getCurrentSdk(): SDK = mockSdk.copy( version = "Version updated" ) diff --git a/apptentive-feedback/src/test/resources/manifest_structure_test.json b/apptentive-feedback/src/test/resources/manifest_structure_test.json index 086fec67..465dc000 100644 --- a/apptentive-feedback/src/test/resources/manifest_structure_test.json +++ b/apptentive-feedback/src/test/resources/manifest_structure_test.json @@ -43,6 +43,13 @@ "device/custom_data/string_qwerty": { "$ends_with": "erty" } + }, + { + "$not": { + "device/custom_data/string_qwerty": { + "$contains": "wre" + } + } } ] } diff --git a/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/ProfileActivity.kt b/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/ProfileActivity.kt index 525808ad..62cae48a 100644 --- a/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/ProfileActivity.kt +++ b/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/ProfileActivity.kt @@ -1,6 +1,7 @@ package apptentive.com.android.feedback.messagecenter.view import android.os.Bundle +import androidx.activity.addCallback import apptentive.com.android.feedback.messagecenter.R import apptentive.com.android.feedback.messagecenter.utils.MessageCenterEvents import apptentive.com.android.feedback.messagecenter.view.custom.ProfileView @@ -69,7 +70,7 @@ internal class ProfileActivity : BaseProfileActivity() { "button_label" to getString(R.string.apptentive_close) ) ) - super.onBackPressed() + finish() } ) confirmationDialog.show() @@ -81,12 +82,11 @@ internal class ProfileActivity : BaseProfileActivity() { "button_label" to saveButton.text.toString() ) ) - super.onBackPressed() + finish() } } - } - - override fun onBackPressed() { - viewModel.exitProfileView(profileView.getName(), profileView.getEmail()) + onBackPressedDispatcher.addCallback(this) { + viewModel.exitProfileView(profileView.getName(), profileView.getEmail().trim()) + } } } diff --git a/apptentive-navigate-to-link/src/main/java/apptentive/com/android/feedback/link/view/NavigateTolinkActivity.kt b/apptentive-navigate-to-link/src/main/java/apptentive/com/android/feedback/link/view/NavigateTolinkActivity.kt index ac858c6a..a1324e12 100644 --- a/apptentive-navigate-to-link/src/main/java/apptentive/com/android/feedback/link/view/NavigateTolinkActivity.kt +++ b/apptentive-navigate-to-link/src/main/java/apptentive/com/android/feedback/link/view/NavigateTolinkActivity.kt @@ -2,6 +2,7 @@ package apptentive.com.android.feedback.link.view import android.content.Intent import android.net.Uri +import android.os.Build import android.os.Bundle import android.webkit.ValueCallback import android.webkit.WebChromeClient @@ -44,6 +45,18 @@ internal class NavigateTolinkActivity : BaseNavigateToLinkActivity() { settings.domStorageEnabled = true settings.mediaPlaybackRequiresUserGesture = false settings.javaScriptCanOpenWindowsAutomatically = true + settings.allowFileAccess = false + settings.allowContentAccess = false + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + settings.safeBrowsingEnabled = true + } + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + settings.allowFileAccessFromFileURLs = false + settings.allowUniversalAccessFromFileURLs = false + } + webView.webChromeClient = object : WebChromeClient() { override fun onShowFileChooser( webView: WebView?, diff --git a/build.gradle b/build.gradle index 3599e7e1..81674740 100644 --- a/build.gradle +++ b/build.gradle @@ -67,7 +67,7 @@ buildscript { } project.ext { - sonatypeVersion = '6.9.0' + sonatypeVersion = '6.9.1' jfrogVersion = '6.8.1' // Change this depending on where you are publishing to