From 4b2d12ee7420fb8c85001d2cef8617405c2abe5c Mon Sep 17 00:00:00 2001
From: PoornimaApptentive
<85186738+PoornimaApptentive@users.noreply.github.com>
Date: Wed, 31 Jul 2024 11:31:36 -0700
Subject: [PATCH] Release/6.8.1 (#34)
Releasing 6.8.1
---
.github/workflows/android.yml | 8 +--
CHANGELOG.md | 13 ++++
apptentive-core-test/build.gradle | 4 +-
.../src/main/AndroidManifest.xml | 3 +-
apptentive-core-ui/build.gradle | 4 +-
.../src/main/AndroidManifest.xml | 3 +-
apptentive-core/build.gradle | 8 ++-
apptentive-core/src/main/AndroidManifest.xml | 3 +-
.../com/android/core/ApptentiveException.kt | 6 ++
.../com/android/core/DependencyProvider.kt | 4 +-
apptentive-enjoyment-dialog/build.gradle | 4 +-
.../src/main/AndroidManifest.xml | 3 +-
.../enjoyment/EnjoymentDialogFragment.kt | 7 ++
.../enjoyment/EnjoymentDialogViewModel.kt | 14 +++-
apptentive-example/build.gradle | 5 +-
.../src/main/AndroidManifest.xml | 3 +-
apptentive-feedback-test/build.gradle | 4 +-
.../src/main/AndroidManifest.xml | 3 +-
apptentive-feedback/build.gradle | 4 +-
.../src/main/AndroidManifest.xml | 3 +-
.../feedback/ApptentiveDefaultClient.kt | 8 ++-
.../com/android/feedback/Constants.kt | 2 +-
.../ConversationSerializationException.kt | 6 +-
apptentive-in-app-review/build.gradle | 4 +-
.../InAppReviewInteractionLauncherTest.kt | 8 +--
.../src/main/AndroidManifest.xml | 3 +-
.../src/main/AndroidManifest.xml | 3 +-
apptentive-message-center/build.gradle | 4 +-
.../src/main/AndroidManifest.xml | 3 +-
.../view/BaseMessageCenterActivity.kt | 9 ++-
.../view/MessageCenterActivity.kt | 58 ++++++++--------
.../messagecenter/view/MessageListAdapter.kt | 20 ++++--
.../view/custom/SimpleTouchImageView.kt | 7 +-
apptentive-navigate-to-link/build.gradle | 4 +-
.../src/main/AndroidManifest.xml | 5 +-
.../android/feedback/link/LinkNavigator.kt | 4 +-
.../link/view/NavigateTolinkActivity.kt | 66 ++++++++++++++++++-
apptentive-notes/build.gradle | 4 +-
apptentive-notes/src/main/AndroidManifest.xml | 3 +-
.../textmodal/TextModalDialogFragment.kt | 3 +
.../feedback/textmodal/TextModalViewModel.kt | 26 +++++---
apptentive-ratings/build.gradle | 4 +-
.../src/main/AndroidManifest.xml | 3 +-
.../ratingdialog/RatingDialogFragment.kt | 7 ++
.../ratingdialog/RatingDialogViewModel.kt | 18 ++++-
apptentive-survey/build.gradle | 4 +-
.../src/main/AndroidManifest.xml | 3 +-
.../feedback/survey/BaseSurveyActivity.kt | 3 +
build.gradle | 11 ++--
gradle.properties | 5 +-
gradle/wrapper/gradle-wrapper.properties | 2 +-
51 files changed, 292 insertions(+), 124 deletions(-)
create mode 100644 apptentive-core/src/main/java/apptentive/com/android/core/ApptentiveException.kt
diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index 102287dd..6b51b205 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -17,10 +17,10 @@ jobs:
steps:
- uses: actions/checkout@v3
- - name: set up JDK 11
+ - name: set up JDK 17
uses: actions/setup-java@v3
with:
- java-version: '11'
+ java-version: '17'
distribution: 'temurin'
cache: gradle
@@ -39,10 +39,10 @@ jobs:
steps:
- uses: actions/checkout@v3
- - name: set up JDK 11
+ - name: set up JDK 17
uses: actions/setup-java@v3
with:
- java-version: '11'
+ java-version: '17'
distribution: 'temurin'
cache: gradle
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 90400f17..9e3984df 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,16 @@
+# 2024-07-31 - v6.8.1
+
+### Fixes
+* Alchemer Survey file upload now working in in-app mode
+* Alchemer Survey video sentiment is now working in in-app mode
+* Alchemer Survey title will display as the survey header in in-app mode
+* Cache the Message Center's input field values for the next time if not updated
+
+### Improvements
+* Upgraded SDK target to Android 14 (API level 34)
+* Upgraded Gradle version to 8.0
+* Prevent the SDK from crashing after the dependencies are garbage collected
+
# 2024-05-29 - v6.8.0
### New Features
* Advanced Customer Research support to show Alchemer long form surveys through prompts
diff --git a/apptentive-core-test/build.gradle b/apptentive-core-test/build.gradle
index bdda62e5..d365ab20 100644
--- a/apptentive-core-test/build.gradle
+++ b/apptentive-core-test/build.gradle
@@ -3,8 +3,7 @@ apply plugin: 'kotlin-android'
apply plugin: 'org.jlleitschuh.gradle.ktlint'
android {
- compileSdkVersion rootProject.compileSdkVersion
- buildToolsVersion rootProject.buildToolsVersion
+ compileSdk rootProject.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.minSdkVersion
@@ -20,6 +19,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ namespace 'test.com.test'
}
dependencies {
diff --git a/apptentive-core-test/src/main/AndroidManifest.xml b/apptentive-core-test/src/main/AndroidManifest.xml
index 05184c87..94cbbcfc 100644
--- a/apptentive-core-test/src/main/AndroidManifest.xml
+++ b/apptentive-core-test/src/main/AndroidManifest.xml
@@ -1,2 +1 @@
-
+
diff --git a/apptentive-core-ui/build.gradle b/apptentive-core-ui/build.gradle
index 9cc7321d..d83d1032 100644
--- a/apptentive-core-ui/build.gradle
+++ b/apptentive-core-ui/build.gradle
@@ -5,8 +5,7 @@ plugins {
}
android {
- compileSdkVersion rootProject.compileSdkVersion
- buildToolsVersion rootProject.buildToolsVersion
+ compileSdk rootProject.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.minSdkVersion
@@ -22,6 +21,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ namespace 'apptentive.com.android'
}
dependencies {
diff --git a/apptentive-core-ui/src/main/AndroidManifest.xml b/apptentive-core-ui/src/main/AndroidManifest.xml
index a7b04aab..a5918e68 100644
--- a/apptentive-core-ui/src/main/AndroidManifest.xml
+++ b/apptentive-core-ui/src/main/AndroidManifest.xml
@@ -1,5 +1,4 @@
-
+
\ No newline at end of file
diff --git a/apptentive-core/build.gradle b/apptentive-core/build.gradle
index f4aa3fc9..c813ddf7 100644
--- a/apptentive-core/build.gradle
+++ b/apptentive-core/build.gradle
@@ -1,10 +1,11 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'org.jlleitschuh.gradle.ktlint'
android {
- compileSdkVersion rootProject.compileSdkVersion
- buildToolsVersion rootProject.buildToolsVersion
+ compileSdk rootProject.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.minSdkVersion
@@ -25,6 +26,7 @@ android {
warningsAsErrors true
abortOnError true
}
+ namespace 'apptentive.com.android.core'
}
dependencies {
@@ -48,7 +50,7 @@ project.ext {
artifactId = 'apptentive-core'
}
-tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
+tasks.withType(KotlinCompile).configureEach {
kotlinOptions {
freeCompilerArgs += [
//'-Xexplicit-api=warning', // or '-Xexplicit-api=strict'
diff --git a/apptentive-core/src/main/AndroidManifest.xml b/apptentive-core/src/main/AndroidManifest.xml
index c5b906e8..91a36692 100644
--- a/apptentive-core/src/main/AndroidManifest.xml
+++ b/apptentive-core/src/main/AndroidManifest.xml
@@ -1,5 +1,4 @@
-
+
diff --git a/apptentive-core/src/main/java/apptentive/com/android/core/ApptentiveException.kt b/apptentive-core/src/main/java/apptentive/com/android/core/ApptentiveException.kt
new file mode 100644
index 00000000..b9e5dce9
--- /dev/null
+++ b/apptentive-core/src/main/java/apptentive/com/android/core/ApptentiveException.kt
@@ -0,0 +1,6 @@
+package apptentive.com.android.core
+
+import apptentive.com.android.util.InternalUseOnly
+
+@InternalUseOnly
+open class ApptentiveException(message: String, cause: Throwable? = null) : Exception(message, cause)
diff --git a/apptentive-core/src/main/java/apptentive/com/android/core/DependencyProvider.kt b/apptentive-core/src/main/java/apptentive/com/android/core/DependencyProvider.kt
index 562f53e2..2c7f25d2 100644
--- a/apptentive-core/src/main/java/apptentive/com/android/core/DependencyProvider.kt
+++ b/apptentive-core/src/main/java/apptentive/com/android/core/DependencyProvider.kt
@@ -25,7 +25,9 @@ object DependencyProvider {
lookup[T::class.java] != null
inline fun of(): T {
- val provider = lookup[T::class.java] ?: throw IllegalArgumentException("Provider is not registered: ${T::class.java}")
+ val provider = lookup[T::class.java] ?: throw MissingProviderException("Provider is not registered: ${T::class.java}")
return provider.get() as T
}
}
+
+class MissingProviderException(message: String, cause: Throwable? = null) : ApptentiveException(message, cause)
diff --git a/apptentive-enjoyment-dialog/build.gradle b/apptentive-enjoyment-dialog/build.gradle
index 52fef27d..ac9eb9a2 100644
--- a/apptentive-enjoyment-dialog/build.gradle
+++ b/apptentive-enjoyment-dialog/build.gradle
@@ -3,8 +3,7 @@ apply plugin: 'kotlin-android'
apply plugin: 'org.jlleitschuh.gradle.ktlint'
android {
- compileSdkVersion rootProject.compileSdkVersion
- buildToolsVersion rootProject.buildToolsVersion
+ compileSdk rootProject.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.minSdkVersion
@@ -20,6 +19,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ namespace 'apptentive.com.android.feedback.enjoyment'
}
dependencies {
diff --git a/apptentive-enjoyment-dialog/src/main/AndroidManifest.xml b/apptentive-enjoyment-dialog/src/main/AndroidManifest.xml
index 41c98fb0..94cbbcfc 100644
--- a/apptentive-enjoyment-dialog/src/main/AndroidManifest.xml
+++ b/apptentive-enjoyment-dialog/src/main/AndroidManifest.xml
@@ -1,2 +1 @@
-
+
diff --git a/apptentive-enjoyment-dialog/src/main/java/apptentive/com/android/feedback/enjoyment/EnjoymentDialogFragment.kt b/apptentive-enjoyment-dialog/src/main/java/apptentive/com/android/feedback/enjoyment/EnjoymentDialogFragment.kt
index 2af18cf6..c07d038d 100644
--- a/apptentive-enjoyment-dialog/src/main/java/apptentive/com/android/feedback/enjoyment/EnjoymentDialogFragment.kt
+++ b/apptentive-enjoyment-dialog/src/main/java/apptentive/com/android/feedback/enjoyment/EnjoymentDialogFragment.kt
@@ -75,6 +75,13 @@ internal class EnjoymentDialogFragment : DialogFragment(), ApptentiveActivityInf
}
}
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ viewModel.dismissInteraction.observe(this) {
+ dismiss()
+ }
+ }
+
override fun onCancel(dialog: DialogInterface) {
viewModel.onCancel()
super.onCancel(dialog)
diff --git a/apptentive-enjoyment-dialog/src/main/java/apptentive/com/android/feedback/enjoyment/EnjoymentDialogViewModel.kt b/apptentive-enjoyment-dialog/src/main/java/apptentive/com/android/feedback/enjoyment/EnjoymentDialogViewModel.kt
index b7caabe4..952d9836 100644
--- a/apptentive-enjoyment-dialog/src/main/java/apptentive/com/android/feedback/enjoyment/EnjoymentDialogViewModel.kt
+++ b/apptentive-enjoyment-dialog/src/main/java/apptentive/com/android/feedback/enjoyment/EnjoymentDialogViewModel.kt
@@ -2,6 +2,9 @@ package apptentive.com.android.feedback.enjoyment
import androidx.lifecycle.ViewModel
import apptentive.com.android.core.DependencyProvider
+import apptentive.com.android.core.LiveEvent
+import apptentive.com.android.core.MissingProviderException
+import apptentive.com.android.feedback.engagement.EngagementContext
import apptentive.com.android.feedback.engagement.EngagementContextFactory
import apptentive.com.android.feedback.engagement.Event
import apptentive.com.android.feedback.utils.getInteractionBackup
@@ -9,7 +12,14 @@ import apptentive.com.android.util.Log
import apptentive.com.android.util.LogTags.INTERACTIONS
internal class EnjoymentDialogViewModel : ViewModel() {
- private val context = DependencyProvider.of().engagementContext()
+ val dismissInteraction: LiveEvent = LiveEvent()
+ private val context: EngagementContext? = try {
+ DependencyProvider.of().engagementContext()
+ } catch (exception: MissingProviderException) {
+ dismissInteraction.postValue(Unit)
+ Log.e(INTERACTIONS, "EngagementContextFactory is not registered, cannot launch EnjoymentDialogViewModel", exception)
+ null
+ }
private val interaction: EnjoymentDialogInteraction = try {
DependencyProvider.of().getEnjoymentDialogInteraction()
@@ -42,7 +52,7 @@ internal class EnjoymentDialogViewModel : ViewModel() {
}
private fun engageCodePoint(name: String) {
- context.executors.state.execute {
+ context?.executors?.state?.execute {
context.engage(
event = Event.internal(name, interaction.type),
interactionId = interaction.id
diff --git a/apptentive-example/build.gradle b/apptentive-example/build.gradle
index a9a40cdb..fd4f7c1c 100644
--- a/apptentive-example/build.gradle
+++ b/apptentive-example/build.gradle
@@ -4,15 +4,16 @@ plugins {
}
android {
- compileSdk 31
+ compileSdk 34
defaultConfig {
applicationId "com.apptentive.apptentive_example"
minSdk 21
- targetSdk 31
+ targetSdk 34
versionCode 1
versionName "1.0"
}
+ namespace 'com.apptentive.apptentive_example'
}
dependencies {
diff --git a/apptentive-example/src/main/AndroidManifest.xml b/apptentive-example/src/main/AndroidManifest.xml
index 30b7b839..da1df46d 100644
--- a/apptentive-example/src/main/AndroidManifest.xml
+++ b/apptentive-example/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
diff --git a/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/BaseMessageCenterActivity.kt b/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/BaseMessageCenterActivity.kt
index bd41390a..c8fb8f46 100644
--- a/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/BaseMessageCenterActivity.kt
+++ b/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/BaseMessageCenterActivity.kt
@@ -3,6 +3,7 @@ package apptentive.com.android.feedback.messagecenter.view
import android.app.Activity
import android.os.Bundle
import androidx.activity.viewModels
+import apptentive.com.android.core.MissingProviderException
import apptentive.com.android.feedback.Apptentive
import apptentive.com.android.feedback.ApptentiveActivityInfo
import apptentive.com.android.feedback.dependencyprovider.createMessageCenterViewModel
@@ -25,7 +26,13 @@ open class BaseMessageCenterActivity : ApptentiveViewModelActivity(), Apptentive
* and managing messages for [MessageCenterActivity]
*/
val viewModel: MessageCenterViewModel by viewModels {
- ViewModelFactory { createMessageCenterViewModel() }
+ try {
+ ViewModelFactory { createMessageCenterViewModel() }
+ } catch (exception: MissingProviderException) {
+ throw MissingProviderException("One or more dependency providers are not registered $exception")
+ } catch (exception: Exception) {
+ throw IllegalStateException("Issue creating MessageCenterViewModel $exception")
+ }
}
override fun onCreate(savedInstanceState: Bundle?) {
diff --git a/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/MessageCenterActivity.kt b/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/MessageCenterActivity.kt
index e915a70e..9d0993a6 100644
--- a/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/MessageCenterActivity.kt
+++ b/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/MessageCenterActivity.kt
@@ -37,6 +37,7 @@ import apptentive.com.android.serialization.json.JsonConverter
import apptentive.com.android.ui.hideSoftKeyboard
import apptentive.com.android.ui.startViewModelActivity
import apptentive.com.android.util.Log
+import apptentive.com.android.util.LogTags.MESSAGE_CENTER
import apptentive.com.android.util.LogTags.PUSH_NOTIFICATION
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.textview.MaterialTextView
@@ -87,32 +88,37 @@ internal class MessageCenterActivity : BaseMessageCenterActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.apptentive_activity_message_center)
- rootLayout = findViewById(R.id.apptentive_root)
- topAppBar = findViewById(R.id.apptentive_toolbar)
- topAppBarTitle = findViewById(R.id.apptentive_message_center_title)
- messageText = findViewById(R.id.apptentive_composer_text)
- attachmentsLayout = findViewById(R.id.apptentive_composer_attachments_layout)
- attachmentButton = findViewById(R.id.apptentive_attachment_button)
- sendButton = findViewById(R.id.apptentive_send_message_button)
- messageList = findViewById(R.id.apptentive_message_list)
- composerErrorView = findViewById(R.id.apptentive_composer_error)
- title = viewModel.title
- topAppBar.title = ""
- topAppBarTitle.text = viewModel.title
- messageText.hint = viewModel.composerHint
- messageListAdapter = MessageListAdapter(viewModel)
- messageList.adapter = messageListAdapter
- messageListAdapter.submitList(viewModel.buildMessageViewDataModel()) {
- scrollRecyclerToFirstUnreadOrLastItem()
- }
- messageList.itemAnimator = null
+ try {
+ rootLayout = findViewById(R.id.apptentive_root)
+ topAppBar = findViewById(R.id.apptentive_toolbar)
+ topAppBarTitle = findViewById(R.id.apptentive_message_center_title)
+ messageText = findViewById(R.id.apptentive_composer_text)
+ attachmentsLayout = findViewById(R.id.apptentive_composer_attachments_layout)
+ attachmentButton = findViewById(R.id.apptentive_attachment_button)
+ sendButton = findViewById(R.id.apptentive_send_message_button)
+ messageList = findViewById(R.id.apptentive_message_list)
+ composerErrorView = findViewById(R.id.apptentive_composer_error)
+ title = viewModel.title
+ topAppBar.title = ""
+ topAppBarTitle.text = viewModel.title
+ messageText.hint = viewModel.composerHint
+ messageListAdapter = MessageListAdapter(viewModel)
+ messageList.adapter = messageListAdapter
+ messageListAdapter.submitList(viewModel.buildMessageViewDataModel()) {
+ scrollRecyclerToFirstUnreadOrLastItem()
+ }
+ messageList.itemAnimator = null
- // SupportActionBar should be set before setting NavigationOnClickListener
- setSupportActionBar(topAppBar)
+ // SupportActionBar should be set before setting NavigationOnClickListener
+ setSupportActionBar(topAppBar)
- addObservers()
- setListeners()
- getPushNotificationPermission()
+ addObservers()
+ setListeners()
+ getPushNotificationPermission()
+ } catch (e: Exception) {
+ Log.e(MESSAGE_CENTER, "Error in onCreate", e)
+ finish()
+ }
}
private fun addObservers() {
@@ -205,6 +211,7 @@ internal class MessageCenterActivity : BaseMessageCenterActivity() {
}
attachmentButton.setOnClickListener {
+ handleDraftMessage(true)
selectImage.launch("image/*")
}
@@ -272,9 +279,8 @@ internal class MessageCenterActivity : BaseMessageCenterActivity() {
}
viewModel.addAttachments(draftAttachments)
}
-
// Restore profile view
- if (messageListAdapter.isProfileViewVisible()) {
+ if (viewModel.isProfileViewVisible()) {
val name = draftSharedPrefs.getString(MESSAGE_CENTER_PROFILE_NAME, "")
val email = draftSharedPrefs.getString(MESSAGE_CENTER_PROFILE_EMAIL, "")
messageListAdapter.updateEmail(email)
diff --git a/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/MessageListAdapter.kt b/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/MessageListAdapter.kt
index ffb3f9d8..09f5b6b8 100644
--- a/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/MessageListAdapter.kt
+++ b/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/MessageListAdapter.kt
@@ -31,6 +31,8 @@ internal class MessageListAdapter(private val messageViewModel: MessageCenterVie
ListAdapter(DiffCallback()) {
private var profileView: ProfileView? = null
+ private var restoreEmailFromDraft: String = ""
+ private var restoreNameFromDraft: String = ""
companion object {
private const val TYPE_HEADER = 0
@@ -51,15 +53,23 @@ internal class MessageListAdapter(private val messageViewModel: MessageCenterVie
}
fun updateEmail(email: String?) {
- email?.let { profileView?.updateEmail(email) }
+ email?.let {
+ if (profileView != null)
+ profileView?.updateEmail(email)
+ else
+ restoreEmailFromDraft = email
+ }
}
fun updateName(name: String?) {
- name?.let { profileView?.updateName(name) }
+ name?.let {
+ if (profileView != null)
+ profileView?.updateName(name)
+ else
+ restoreNameFromDraft = name
+ }
}
- fun isProfileViewVisible(): Boolean = profileView?.isVisible == true
-
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return when (viewType) {
@@ -193,6 +203,8 @@ internal class MessageListAdapter(private val messageViewModel: MessageCenterVie
profileView?.setEmailHint(viewData.emailHint)
profileView?.setNameHint(viewData.nameHint)
profileView?.isVisible = viewData.showProfile
+ profileView?.updateName(restoreNameFromDraft)
+ profileView?.updateEmail(restoreEmailFromDraft)
}
}
}
diff --git a/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/custom/SimpleTouchImageView.kt b/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/custom/SimpleTouchImageView.kt
index 30646a06..b89e5502 100644
--- a/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/custom/SimpleTouchImageView.kt
+++ b/apptentive-message-center/src/main/java/apptentive/com/android/feedback/messagecenter/view/custom/SimpleTouchImageView.kt
@@ -702,7 +702,12 @@ internal class SimpleTouchImageView @JvmOverloads constructor(context: Context,
performLongClick()
}
- override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
+ override fun onFling(
+ e1: MotionEvent?,
+ e2: MotionEvent,
+ velocityX: Float,
+ velocityY: Float
+ ): Boolean {
// If a previous fling is still active, it should be cancelled so that two flings
// are not run simultaneously.
fling?.cancelFling()
diff --git a/apptentive-navigate-to-link/build.gradle b/apptentive-navigate-to-link/build.gradle
index 7ed8a622..a7b46083 100644
--- a/apptentive-navigate-to-link/build.gradle
+++ b/apptentive-navigate-to-link/build.gradle
@@ -5,8 +5,7 @@ plugins {
}
android {
- compileSdkVersion rootProject.compileSdkVersion
- buildToolsVersion rootProject.buildToolsVersion
+ compileSdk rootProject.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.minSdkVersion
@@ -22,6 +21,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ namespace 'apptentive.com.android.feedback.link'
}
dependencies {
diff --git a/apptentive-navigate-to-link/src/main/AndroidManifest.xml b/apptentive-navigate-to-link/src/main/AndroidManifest.xml
index f2643f56..4e098fd6 100644
--- a/apptentive-navigate-to-link/src/main/AndroidManifest.xml
+++ b/apptentive-navigate-to-link/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
+ xmlns:tools="http://schemas.android.com/tools">
@@ -15,7 +15,8 @@
+ android:theme="@style/Theme.Apptentive"
+ android:usesCleartextTraffic = "true" />
\ No newline at end of file
diff --git a/apptentive-navigate-to-link/src/main/java/apptentive/com/android/feedback/link/LinkNavigator.kt b/apptentive-navigate-to-link/src/main/java/apptentive/com/android/feedback/link/LinkNavigator.kt
index 7b163ed6..dd89e020 100644
--- a/apptentive-navigate-to-link/src/main/java/apptentive/com/android/feedback/link/LinkNavigator.kt
+++ b/apptentive-navigate-to-link/src/main/java/apptentive/com/android/feedback/link/LinkNavigator.kt
@@ -3,6 +3,7 @@ package apptentive.com.android.feedback.link
import android.content.Context
import android.content.Intent
import android.net.Uri
+import android.os.Build
import android.os.Bundle
import androidx.annotation.MainThread
import androidx.annotation.VisibleForTesting
@@ -23,7 +24,8 @@ internal object LinkNavigator {
context = context,
interaction = interaction
) {
- if (interaction.target == NavigateToLinkInteraction.Target.self) {
+ // The web view doesn't have a good support prior to Android P
+ if (interaction.target == NavigateToLinkInteraction.Target.self && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
context.getAppActivity().startViewModelActivity(
extras = Bundle().apply {
putString("linkUrl", interaction.url)
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 4f897011..ac858c6a 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
@@ -1,17 +1,35 @@
package apptentive.com.android.feedback.link.view
+import android.content.Intent
+import android.net.Uri
import android.os.Bundle
+import android.webkit.ValueCallback
+import android.webkit.WebChromeClient
import android.webkit.WebView
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
import apptentive.com.android.feedback.link.R
import apptentive.com.android.ui.hideSoftKeyboard
+import apptentive.com.android.util.Log
+import apptentive.com.android.util.LogTags
import com.google.android.material.appbar.MaterialToolbar
internal class NavigateTolinkActivity : BaseNavigateToLinkActivity() {
private lateinit var webView: WebView
+ private var uploadMessage: ValueCallback>? = null
+ private lateinit var fileChooserLauncher: ActivityResultLauncher
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.apptentive_activity_navigate_to_link)
+ // Register the ActivityResultLauncher
+ fileChooserLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
+ if (uploadMessage == null) return@registerForActivityResult
+ uploadMessage?.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(result.resultCode, result.data))
+ uploadMessage = null
+ }
+
supportActionBar?.hide()
val topAppBar = findViewById(R.id.apptentive_top_app_bar)
@@ -21,7 +39,42 @@ internal class NavigateTolinkActivity : BaseNavigateToLinkActivity() {
}
webView = findViewById(R.id.apptentive_webview_navigate_to_link)
- webView.settings.javaScriptEnabled = true
+ val settings = webView.settings
+ settings.javaScriptEnabled = true
+ settings.domStorageEnabled = true
+ settings.mediaPlaybackRequiresUserGesture = false
+ settings.javaScriptCanOpenWindowsAutomatically = true
+ webView.webChromeClient = object : WebChromeClient() {
+ override fun onShowFileChooser(
+ webView: WebView?,
+ filePathCallback: ValueCallback>?,
+ fileChooserParams: FileChooserParams?
+ ): Boolean {
+ if (uploadMessage != null) {
+ uploadMessage?.onReceiveValue(null)
+ uploadMessage = null
+ }
+
+ Log.i(LogTags.SURVEY, "Detected file upload using alchemer survey")
+
+ uploadMessage = filePathCallback
+ val intent = fileChooserParams?.createIntent()
+ try {
+ fileChooserLauncher.launch(intent)
+ } catch (e: Exception) {
+ Log.e(LogTags.SURVEY, "Error launching file chooser", e)
+ uploadMessage = null
+ return false
+ }
+ return true
+ }
+
+ override fun onReceivedTitle(view: WebView?, title: String?) {
+ super.onReceivedTitle(view, title)
+ title?.let { topAppBar.title = it }
+ }
+ }
+
val url = intent.getStringExtra("linkUrl")
if (savedInstanceState != null) {
webView.restoreState(savedInstanceState)
@@ -33,4 +86,15 @@ internal class NavigateTolinkActivity : BaseNavigateToLinkActivity() {
super.onSaveInstanceState(outState)
webView.saveState(outState)
}
+
+ override fun onDestroy() {
+ super.onDestroy()
+ webView.apply {
+ clearHistory()
+ clearCache(true)
+ onPause()
+ removeAllViews()
+ destroy()
+ }
+ }
}
diff --git a/apptentive-notes/build.gradle b/apptentive-notes/build.gradle
index dd74c629..6647ce13 100644
--- a/apptentive-notes/build.gradle
+++ b/apptentive-notes/build.gradle
@@ -5,8 +5,7 @@ plugins {
}
android {
- compileSdkVersion rootProject.compileSdkVersion
- buildToolsVersion rootProject.buildToolsVersion
+ compileSdk rootProject.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.minSdkVersion
@@ -22,6 +21,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ namespace 'apptentive.com.android.feedback.notes'
}
dependencies {
diff --git a/apptentive-notes/src/main/AndroidManifest.xml b/apptentive-notes/src/main/AndroidManifest.xml
index e66744d6..6e5ca417 100644
--- a/apptentive-notes/src/main/AndroidManifest.xml
+++ b/apptentive-notes/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
diff --git a/apptentive-notes/src/main/java/apptentive/com/android/feedback/textmodal/TextModalDialogFragment.kt b/apptentive-notes/src/main/java/apptentive/com/android/feedback/textmodal/TextModalDialogFragment.kt
index 93350ed9..c4c3ab7f 100644
--- a/apptentive-notes/src/main/java/apptentive/com/android/feedback/textmodal/TextModalDialogFragment.kt
+++ b/apptentive-notes/src/main/java/apptentive/com/android/feedback/textmodal/TextModalDialogFragment.kt
@@ -139,6 +139,9 @@ internal class TextModalDialogFragment : DialogFragment(), ApptentiveActivityInf
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ viewModel.dismissInteraction.observe(this) {
+ dismiss()
+ }
viewModel.noteHeaderBitmapStream.observe(this) { bitmap ->
setupImage(bitmap)
}
diff --git a/apptentive-notes/src/main/java/apptentive/com/android/feedback/textmodal/TextModalViewModel.kt b/apptentive-notes/src/main/java/apptentive/com/android/feedback/textmodal/TextModalViewModel.kt
index 0e482984..be534f5c 100644
--- a/apptentive-notes/src/main/java/apptentive/com/android/feedback/textmodal/TextModalViewModel.kt
+++ b/apptentive-notes/src/main/java/apptentive/com/android/feedback/textmodal/TextModalViewModel.kt
@@ -11,6 +11,7 @@ import apptentive.com.android.core.DependencyProvider
import apptentive.com.android.core.LiveEvent
import apptentive.com.android.feedback.EngagementResult
import apptentive.com.android.feedback.PrefetchManager
+import apptentive.com.android.feedback.engagement.EngagementContext
import apptentive.com.android.feedback.engagement.EngagementContextFactory
import apptentive.com.android.feedback.engagement.Event
import apptentive.com.android.feedback.engagement.interactions.InteractionResponse
@@ -20,7 +21,14 @@ import apptentive.com.android.util.Log
import apptentive.com.android.util.LogTags.INTERACTIONS
internal class TextModalViewModel : ViewModel() {
- private val context = DependencyProvider.of().engagementContext()
+ val dismissInteraction: LiveEvent = LiveEvent()
+ private val context: EngagementContext? = try {
+ DependencyProvider.of().engagementContext()
+ } catch (exception: Exception) {
+ Log.e(INTERACTIONS, "Provider is not registered, could not create engagement context", exception)
+ dismissInteraction.postValue(Unit)
+ null
+ }
private val interaction: TextModalModel = try {
DependencyProvider.of().getTextModalModel()
@@ -51,7 +59,7 @@ internal class TextModalViewModel : ViewModel() {
title = action.label,
callback = {
// invoke action
- context.executors.state.execute(createActionCallback(action, index))
+ context?.executors?.state?.execute(createActionCallback(action, index))
// dismiss UI
onDismiss?.invoke()
@@ -62,7 +70,7 @@ internal class TextModalViewModel : ViewModel() {
title = action.label,
callback = {
// invoke action
- context.executors.state.execute(createActionCallback(action, index))
+ context?.executors?.state?.execute(createActionCallback(action, index))
// dismiss UI
onDismiss?.invoke()
@@ -76,7 +84,7 @@ internal class TextModalViewModel : ViewModel() {
private val noteHeaderEvent = LiveEvent()
val noteHeaderBitmapStream: LiveData = noteHeaderEvent
init {
- context.executors.state.execute {
+ context?.executors?.state?.execute {
interaction.richContent?.url?.let { url ->
PrefetchManager.getImage(url)?.let {
isWiderImage = it.width > MAX_IMAGE_WIDTH
@@ -87,7 +95,7 @@ internal class TextModalViewModel : ViewModel() {
}
fun onCancel() {
- context.executors.state.execute {
+ context?.executors?.state?.execute {
engageCodePoint(CODE_POINT_CANCEL)
}
}
@@ -97,7 +105,7 @@ internal class TextModalViewModel : ViewModel() {
data: Map? = null,
actionId: String? = null
) {
- context.engage(
+ context?.engage(
event = Event.internal(codePoint, interaction = "TextModal"),
interactionId = interaction.id,
data = data,
@@ -110,7 +118,7 @@ internal class TextModalViewModel : ViewModel() {
private fun createActionCallback(action: TextModalModel.Action, index: Int): Callback = when (action) {
is TextModalModel.Action.Dismiss -> {
{
- context.executors.state.execute {
+ context?.executors?.state?.execute {
Log.i(INTERACTIONS, "Note dismissed")
// engage event
val data = createEventData(action, index)
@@ -120,7 +128,7 @@ internal class TextModalViewModel : ViewModel() {
}
is TextModalModel.Action.Invoke -> {
{
- context.executors.state.execute {
+ context?.executors?.state?.execute {
Log.i(INTERACTIONS, "Note action invoked")
// run invocation
@@ -134,7 +142,7 @@ internal class TextModalViewModel : ViewModel() {
}
is TextModalModel.Action.Event -> {
{
- context.executors.state.execute {
+ context?.executors?.state?.execute {
Log.i(INTERACTIONS, "Note event engaged")
// engage target event
diff --git a/apptentive-ratings/build.gradle b/apptentive-ratings/build.gradle
index 8ab09c23..457f6a65 100644
--- a/apptentive-ratings/build.gradle
+++ b/apptentive-ratings/build.gradle
@@ -5,8 +5,7 @@ plugins {
}
android {
- compileSdkVersion rootProject.compileSdkVersion
- buildToolsVersion rootProject.buildToolsVersion
+ compileSdk rootProject.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.minSdkVersion
@@ -22,6 +21,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ namespace 'apptentive.com.android.feedback.ratings'
}
dependencies {
diff --git a/apptentive-ratings/src/main/AndroidManifest.xml b/apptentive-ratings/src/main/AndroidManifest.xml
index 62e569de..6e5ca417 100644
--- a/apptentive-ratings/src/main/AndroidManifest.xml
+++ b/apptentive-ratings/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
diff --git a/apptentive-ratings/src/main/java/apptentive/com/android/feedback/ratingdialog/RatingDialogFragment.kt b/apptentive-ratings/src/main/java/apptentive/com/android/feedback/ratingdialog/RatingDialogFragment.kt
index 63d1f564..6d6a74f8 100644
--- a/apptentive-ratings/src/main/java/apptentive/com/android/feedback/ratingdialog/RatingDialogFragment.kt
+++ b/apptentive-ratings/src/main/java/apptentive/com/android/feedback/ratingdialog/RatingDialogFragment.kt
@@ -70,6 +70,13 @@ internal class RatingDialogFragment : DialogFragment(), ApptentiveActivityInfo {
}
}
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ viewModel.dismissInteraction.observe(this) {
+ dismiss()
+ }
+ }
+
override fun onCancel(dialog: DialogInterface) {
viewModel.onCancel()
super.onCancel(dialog)
diff --git a/apptentive-ratings/src/main/java/apptentive/com/android/feedback/ratingdialog/RatingDialogViewModel.kt b/apptentive-ratings/src/main/java/apptentive/com/android/feedback/ratingdialog/RatingDialogViewModel.kt
index afe760e9..7f023c04 100644
--- a/apptentive-ratings/src/main/java/apptentive/com/android/feedback/ratingdialog/RatingDialogViewModel.kt
+++ b/apptentive-ratings/src/main/java/apptentive/com/android/feedback/ratingdialog/RatingDialogViewModel.kt
@@ -2,6 +2,9 @@ package apptentive.com.android.feedback.ratingdialog
import androidx.lifecycle.ViewModel
import apptentive.com.android.core.DependencyProvider
+import apptentive.com.android.core.LiveEvent
+import apptentive.com.android.core.MissingProviderException
+import apptentive.com.android.feedback.engagement.EngagementContext
import apptentive.com.android.feedback.engagement.EngagementContextFactory
import apptentive.com.android.feedback.engagement.Event
import apptentive.com.android.feedback.utils.getInteractionBackup
@@ -9,7 +12,18 @@ import apptentive.com.android.util.Log
import apptentive.com.android.util.LogTags.INTERACTIONS
internal class RatingDialogViewModel : ViewModel() {
- private val context = DependencyProvider.of().engagementContext()
+ val dismissInteraction = LiveEvent()
+ private val context: EngagementContext? = try {
+ DependencyProvider.of().engagementContext()
+ } catch (exception: MissingProviderException) {
+ dismissInteraction.postValue(Unit)
+ Log.e(
+ INTERACTIONS,
+ "EngagementContextFactory is not registered, cannot launch RatingDialogViewModel",
+ exception
+ )
+ null
+ }
private val interaction: RatingDialogInteraction = try {
DependencyProvider.of().getRatingDialogInteraction()
} catch (exception: Exception) {
@@ -40,7 +54,7 @@ internal class RatingDialogViewModel : ViewModel() {
}
private fun engageCodePoint(name: String) {
- context.executors.state.execute {
+ context?.executors?.state?.execute {
context.engage(
event = Event.internal(name, interaction.type),
interactionId = interaction.id
diff --git a/apptentive-survey/build.gradle b/apptentive-survey/build.gradle
index 88f68321..69fb8812 100644
--- a/apptentive-survey/build.gradle
+++ b/apptentive-survey/build.gradle
@@ -5,8 +5,7 @@ plugins {
}
android {
- compileSdkVersion rootProject.compileSdkVersion
- buildToolsVersion rootProject.buildToolsVersion
+ compileSdk rootProject.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.minSdkVersion
@@ -22,6 +21,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ namespace 'apptentive.com.android.feedback.survey'
}
dependencies {
diff --git a/apptentive-survey/src/main/AndroidManifest.xml b/apptentive-survey/src/main/AndroidManifest.xml
index 32c6029d..29871a5e 100644
--- a/apptentive-survey/src/main/AndroidManifest.xml
+++ b/apptentive-survey/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+