diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index c822052f1d13..6dbf16708c3b 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -79,6 +79,7 @@ val ndkEnv = buildMap {
}
}
+val adjustAppToken = project.properties["ADJUST_APP_TOKEN"]
val ncTestServerUsername = providers.gradleProperty("NC_TEST_SERVER_USERNAME").get()
val ncTestServerPassword = providers.gradleProperty("NC_TEST_SERVER_PASSWORD").get()
val ncTestServerBaseUrl = providers.gradleProperty("NC_TEST_SERVER_BASEURL").get()
@@ -116,7 +117,8 @@ android {
buildConfigField("boolean", "CI", ciBuild.toString())
buildConfigField("boolean", "RUNTIME_PERF_ANALYSIS", perfAnalysis.toString())
-
+ // NMC Customization: adjust token
+ buildConfigField("String", "ADJUST_APP_TOKEN", adjustAppToken.toString())
// arguments to be passed to functional tests
testInstrumentationRunner = if (shotTest) "com.karumi.shot.ShotTestRunner"
else "com.nextcloud.client.TestRunner"
@@ -517,6 +519,14 @@ dependencies {
implementation(libs.kotlinx.coroutines.core)
// endregion
+ // NMC region
+ // Adjust SDK --> https://github.com/adjust/android_sdk
+ implementation(libs.adjust.android)
+ implementation(libs.installreferrer)
+ // tealium sdk
+ implementation(libs.tealium.library)
+ // endregion
+
// region Google Play dependencies, upon each update first test: new registration, receive push
add(gplayImplementationConfiguration, libs.bundles.gplay)
// endregion
@@ -532,4 +542,7 @@ dependencies {
// kotlinx.serialization
implementation(libs.kotlinx.serialization.json)
+
+ // NMC: dependency required to capture Advertising ID for Adjust & MoEngage SDK
+ implementation(libs.play.services.ads.identifier)
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1f1c5a60abbe..0670765710e8 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -662,6 +662,17 @@
android:name="com.nextcloud.client.etm.EtmActivity"
android:exported="false"
android:theme="@style/Theme.ownCloud.Toolbar" />
+
+
+
+
+
+
+
+
androidInjector() {
return dispatchingAndroidInjector;
}
+ //NMC Customization
+ private void initMarketTrackingSdks(){
+ TealiumSdkUtils.initialiseTealiumSDK(this);
+ AdjustSdkUtils.initialiseAdjustSDK(this);
+ }
+
public static void setAppTheme(DarkMode mode) {
switch (mode) {
case LIGHT -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
diff --git a/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.kt b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.kt
index 2ef83e482af3..7698e953090e 100644
--- a/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.kt
+++ b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.kt
@@ -60,6 +60,8 @@ import com.nextcloud.repository.ClientRepository
import com.nextcloud.utils.SnackbarUtil
import com.nextcloud.utils.extensions.getParcelableArgument
import com.nextcloud.utils.mdm.MDMConfig
+import com.nmc.android.marketTracking.AdjustSdkUtils
+import com.nmc.android.marketTracking.TealiumSdkUtils
import com.nextcloud.utils.text.LinkFormatter
import com.owncloud.android.MainApp
import com.owncloud.android.R
@@ -970,6 +972,10 @@ open class AuthenticatorActivity :
}
private fun endSuccess() {
+ // NMC: track successful login event
+ AdjustSdkUtils.trackEvent(AdjustSdkUtils.EVENT_TOKEN_SUCCESSFUL_LOGIN, preferences)
+ TealiumSdkUtils.trackEvent(TealiumSdkUtils.EVENT_SUCCESSFUL_LOGIN, preferences)
+
if (!onlyAdd) {
startActivity(postLoginIntent())
}
@@ -1117,6 +1123,12 @@ open class AuthenticatorActivity :
return false // always return false to grant that the software keyboard is hidden anyway
}
+ override fun onStart() {
+ super.onStart()
+ // track screen view when activity is visible
+ TealiumSdkUtils.trackView(TealiumSdkUtils.SCREEN_VIEW_LOGIN, preferences)
+ }
+
// region Operations service
private fun doOnResumeAndBound() {
val binder = operationsServiceBinder ?: return
diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt
index ff83034b36db..4414c00a4ff6 100644
--- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt
+++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt
@@ -76,6 +76,7 @@ import com.nextcloud.utils.extensions.lastFragment
import com.nextcloud.utils.extensions.navigateToAllFiles
import com.nextcloud.utils.extensions.setVisibleIf
import com.nextcloud.utils.view.FastScrollUtils
+import com.nmc.android.marketTracking.TealiumSdkUtils
import com.owncloud.android.MainApp
import com.owncloud.android.R
import com.owncloud.android.authentication.PassCodeManager
@@ -583,6 +584,9 @@ class FileDisplayActivity :
saveLastDisplayedAccountName(accountName)
EventBus.getDefault().post(TokenPushEvent())
checkForNewDevVersionNecessary(applicationContext)
+
+ // NMC: track screen view when activity is visible
+ TealiumSdkUtils.trackView(TealiumSdkUtils.SCREEN_VIEW_FILE_BROWSER, preferences)
}
private fun resolveInitialFile(storageManager: FileDataStorageManager): OCFile? =
diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java
index 6580a0119b24..d7be826ffa70 100644
--- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java
+++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java
@@ -50,6 +50,7 @@
import com.nextcloud.client.network.ClientFactory;
import com.nextcloud.client.network.ConnectivityService;
import com.nextcloud.client.preferences.AppPreferences;
+import com.nmc.android.marketTracking.TealiumSdkUtils;
import com.nextcloud.client.preferences.AppPreferencesImpl;
import com.nextcloud.client.preferences.DarkMode;
import com.nextcloud.client.utils.IntentUtil;
@@ -1237,6 +1238,13 @@ protected void onPostCreate(Bundle savedInstanceState) {
getDelegate().onPostCreate(savedInstanceState);
}
+ @Override
+ protected void onStart() {
+ super.onStart();
+ //track screen view when activity is visible
+ TealiumSdkUtils.trackView(TealiumSdkUtils.SCREEN_VIEW_SETTINGS, preferences);
+ }
+
@Override
protected void onDestroy() {
super.onDestroy();
diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt
index ab5db8acb154..76b80c09d5ca 100644
--- a/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt
+++ b/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt
@@ -9,33 +9,24 @@
package com.owncloud.android.ui.dialog
import android.app.Dialog
-import android.graphics.drawable.Drawable
+import android.content.DialogInterface
import android.os.Bundle
-import android.view.View
-import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.nextcloud.client.account.User
-import com.nextcloud.client.account.UserAccountManager
import com.nextcloud.client.di.Injectable
import com.nextcloud.client.jobs.BackgroundJobManager
import com.nextcloud.client.player.media3.PlaybackModel
-import com.nextcloud.client.utils.IntentUtil
-import com.nextcloud.utils.avatar.AvatarGenerationListener
-import com.nextcloud.utils.avatar.AvatarGenerator
+import com.nextcloud.client.preferences.AppPreferences
+import com.nmc.android.marketTracking.AdjustSdkUtils
+import com.nmc.android.marketTracking.TealiumSdkUtils
import com.nextcloud.utils.extensions.getParcelableArgument
-import com.nextcloud.utils.text.LinkFormatter
import com.owncloud.android.R
-import com.owncloud.android.databinding.AccountRemovalDialogBinding
-import com.owncloud.android.datamodel.FileDataStorageManager
-import com.owncloud.android.ui.dialog.extensions.themeButtons
import com.owncloud.android.utils.theme.ViewThemeUtils
import javax.inject.Inject
-class AccountRemovalDialog :
- DialogFragment(),
- AvatarGenerationListener,
- Injectable {
+// NMC Customization: We don't need two option for logout. On logout directly logout the user locally from the app
+class AccountRemovalDialog : DialogFragment(), Injectable {
@Inject
lateinit var backgroundJobManager: BackgroundJobManager
@@ -47,134 +38,40 @@ class AccountRemovalDialog :
lateinit var playbackModel: PlaybackModel
@Inject
- lateinit var avatarGenerator: AvatarGenerator
+ lateinit var appPreferences: AppPreferences
private var user: User? = null
- private lateinit var alertDialog: AlertDialog
- private var _binding: AccountRemovalDialogBinding? = null
- val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
user = requireArguments().getParcelableArgument(KEY_USER, User::class.java)
}
- override fun onStart() {
- super.onStart()
-
- // disable positive button and apply theming
- alertDialog = dialog as AlertDialog
- alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
-
- viewThemeUtils.platform.themeRadioButton(binding.radioLocalRemove)
- viewThemeUtils.platform.themeRadioButton(binding.radioRequestDeletion)
- alertDialog.themeButtons(viewThemeUtils)
- binding.userName.text = UserAccountManager.getDisplayName(user)
- binding.account.text = user?.let { LinkFormatter.toUnicodeDomain(it.accountName) }
- }
-
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
- _binding = AccountRemovalDialogBinding.inflate(layoutInflater)
-
- // start avatar generation
- setAvatar()
-
- // hide second option when plug-in isn't installed
- if (hasDropAccount()) {
- binding.requestDeletion.visibility = View.VISIBLE
- }
-
- val builder =
- MaterialAlertDialogBuilder(requireActivity())
- .setTitle(R.string.delete_account)
- .setView(binding.root)
- .setNegativeButton(R.string.common_cancel) { _, _ -> }
- .setPositiveButton(R.string.delete_account) { _, _ -> removeAccount() }
-
- // allow selection by clicking on list element
- binding.localRemove.setOnClickListener {
- binding.radioLocalRemove.performClick()
- }
- binding.requestDeletion.setOnClickListener {
- binding.radioRequestDeletion.performClick()
- }
-
- // set listeners for custom radio button list
- binding.radioLocalRemove.setOnClickListener {
- binding.radioRequestDeletion.isChecked = false
- alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).apply {
- text = getText(R.string.delete_account)
- isEnabled = true
+ val builder = MaterialAlertDialogBuilder(requireActivity())
+ .setTitle(R.string.delete_account)
+ .setMessage(resources.getString(R.string.delete_account_warning))
+ .setIcon(R.drawable.ic_warning)
+ .setPositiveButton(R.string.common_ok) { _: DialogInterface?, _: Int ->
+ user?.let { user ->
+ stopMediaPlayerAndHidePip()
+ // track adjust and tealium events on logout confirmed
+ AdjustSdkUtils.trackEvent(AdjustSdkUtils.EVENT_TOKEN_SETTINGS_LOGOUT, appPreferences)
+ TealiumSdkUtils.trackEvent(TealiumSdkUtils.EVENT_SETTINGS_LOGOUT, appPreferences)
+ backgroundJobManager.startAccountRemovalJob(user.accountName, false)
+ }
}
- }
- binding.radioRequestDeletion.setOnClickListener {
- binding.radioLocalRemove.isChecked = false
- alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).apply {
- text = getString(R.string.request_account_deletion_button)
- isEnabled = true
- }
- }
-
- viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireActivity(), builder)
+ .setNegativeButton(R.string.common_cancel, null)
return builder.create()
}
- /**
- * Get value of `drop-account` capability.
- */
- private fun hasDropAccount(): Boolean {
- val capability = FileDataStorageManager(user, context?.contentResolver).getCapability(user)
- return capability.dropAccount.isTrue
- }
-
- /**
- * Start removal of account. Depending on which option is checked, either a browser will open to request deletion,
- * or the local account will be removed immediately.
- */
- private fun removeAccount() {
- user?.let { user ->
- stopMediaPlayerAndHidePip()
- if (binding.radioRequestDeletion.isChecked) {
- IntentUtil.startLinkIntent(requireActivity(), user.server.uri.toString() + DROP_ACCOUNT_URI)
- } else {
- backgroundJobManager.startAccountRemovalJob(user.accountName, false)
- }
- }
- }
-
private fun stopMediaPlayerAndHidePip() {
playbackModel.release()
}
- /**
- * Start avatar generation.
- */
- private fun setAvatar() {
- try {
- val imageView = binding.userIcon
- imageView.tag = user!!.accountName
- avatarGenerator.setAccountAvatar(
- user!!,
- this,
- resources.getDimension(R.dimen.list_item_avatar_icon_radius),
- imageView
- )
- } catch (_: Exception) {
- }
- }
-
- override fun avatarGenerated(avatarDrawable: Drawable?, callContext: Any?) {
- avatarDrawable?.let {
- binding.userIcon.setImageDrawable(it)
- }
- }
-
- override fun shouldCallGeneratedCallback(tag: String?, callContext: Any?): Boolean = binding.userIcon.tag == tag
-
companion object {
private const val KEY_USER = "USER"
- private const val DROP_ACCOUNT_URI = "/settings/user/drop_account"
@JvmStatic
fun newInstance(user: User) = AccountRemovalDialog().apply {
diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.kt
index 7ed558385c64..5afcf4336d74 100644
--- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.kt
+++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.kt
@@ -57,6 +57,7 @@ import com.nextcloud.utils.extensions.getParcelableArgument
import com.nextcloud.utils.mdm.MDMConfig
import com.nextcloud.utils.text.DisplayTextFormatter
import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator
+import com.nmc.android.marketTracking.TealiumSdkUtils
import com.owncloud.android.R
import com.owncloud.android.databinding.FileDetailsFragmentBinding
import com.owncloud.android.datamodel.FileDataStorageManager
@@ -200,6 +201,8 @@ class FileDetailFragment :
super.onStart()
listenForTransferProgress()
EventBus.getDefault().register(this)
+ // NMC: track screen view when fragment is visible
+ TealiumSdkUtils.trackView(TealiumSdkUtils.SCREEN_VIEW_SHARING, preferences)
}
override fun onResume() {
diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.kt
index d56341b621bc..98c3a7a3ad9d 100644
--- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.kt
+++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.kt
@@ -38,6 +38,7 @@ import com.nextcloud.client.account.User
import com.nextcloud.client.account.UserAccountManager
import com.nextcloud.client.di.Injectable
import com.nextcloud.client.network.ClientFactory
+import com.nextcloud.client.preferences.AppPreferences
import com.nextcloud.client.utils.IntentUtil
import com.nextcloud.utils.SnackbarUtil
import com.nextcloud.utils.avatar.AvatarGenerationListener
@@ -48,6 +49,8 @@ import com.nextcloud.utils.extensions.setVisibleIf
import com.nextcloud.utils.extensions.supportsUnifiedShare
import com.nextcloud.utils.extensions.toServerCredentials
import com.nextcloud.utils.mdm.MDMConfig.shareViaUser
+import com.nmc.android.marketTracking.AdjustSdkUtils
+import com.nmc.android.marketTracking.TealiumSdkUtils
import com.owncloud.android.R
import com.owncloud.android.databinding.FileDetailsSharingFragmentBinding
import com.owncloud.android.datamodel.FileDataStorageManager
@@ -120,6 +123,9 @@ class FileDetailSharingFragment :
@Inject
lateinit var avatarGenerator: AvatarGenerator
+ @Inject
+ lateinit var appPreferences: AppPreferences
+
// region lifecycle methods
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -755,6 +761,10 @@ class FileDetailSharingFragment :
// create without password
fileOperationsHelper?.shareFileViaPublicShare(file, null)
+
+ // track event on creating share link
+ AdjustSdkUtils.trackEvent(AdjustSdkUtils.EVENT_TOKEN_CREATE_SHARING_LINK, appPreferences)
+ TealiumSdkUtils.trackEvent(TealiumSdkUtils.EVENT_CREATE_SHARING_LINK, appPreferences)
}
override fun createSecureFileDrop() {
diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.kt
index 22d4f255a9fb..4c780bfbdd95 100644
--- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.kt
+++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.kt
@@ -30,11 +30,13 @@ import com.nextcloud.client.device.DeviceInfo
import com.nextcloud.client.di.Injectable
import com.nextcloud.client.documentscan.AppScanOptionalFeature
import com.nextcloud.utils.BuildHelper.isFlavourGPlay
+import com.nextcloud.client.preferences.AppPreferencesImpl
import com.nextcloud.utils.EditorUtils
import com.nextcloud.utils.extensions.isNetworkAndServerAvailableSuspended
import com.nextcloud.utils.extensions.isTemplateAvailable
import com.nextcloud.utils.extensions.setVisibleIf
import com.owncloud.android.MainApp
+import com.nmc.android.marketTracking.TealiumSdkUtils
import com.owncloud.android.R
import com.owncloud.android.databinding.FileListActionsBottomSheetFragmentBinding
import com.owncloud.android.datamodel.ArbitraryDataProvider
@@ -137,6 +139,14 @@ class OCFileListBottomSheetDialog(
binding.menuUploadFromApp.text = context.getString(R.string.upload_files)
}
}
+
+ // track screen view when fragment is visible
+ TealiumSdkUtils.trackView(
+ TealiumSdkUtils.SCREEN_VIEW_FAB_PLUS,
+ // need to create direct instance of AppPreferences as Injection doesn't work in Dialogs
+ // if we take AppPreferences as parameter in constructor it will affect the other NMC PRs test cases
+ AppPreferencesImpl.fromContext(fileActivity)
+ )
}
private fun checkCreateEncryptedFolderVisibility() {
diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.kt
index 01f945d5f4bb..f7cd864f61dc 100644
--- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.kt
+++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.kt
@@ -66,9 +66,13 @@ import com.nextcloud.utils.extensions.listenEncryptionDialogResult
import com.nextcloud.utils.extensions.logFileSize
import com.nextcloud.utils.extensions.resolveMimeType
import com.nextcloud.utils.extensions.slideHideBottomBehavior
+import com.nmc.android.marketTracking.AdjustSdkUtils
+import com.nmc.android.marketTracking.TrackingScanInterfaceImpl
+import com.nmc.android.marketTracking.TealiumSdkUtils
import com.nextcloud.utils.fileNameValidator.FileNameValidator
import com.nextcloud.utils.thumbnail.ThumbnailGenerator
import com.nextcloud.utils.view.FastScrollUtils
+import com.nmc.android.marketTracking.TrackingScanInterface
import com.owncloud.android.MainApp
import com.owncloud.android.R
import com.owncloud.android.datamodel.ArbitraryDataProvider
@@ -170,6 +174,13 @@ open class OCFileListFragment :
@Inject
lateinit var deviceInfo: DeviceInfo
+ /**
+ * Things to note about both the branches. 1. nmc/1867-scanbot branch: --> interface won't be initialised -->
+ * calling of interface method will be done here 2. nmc/1925-market_tracking --> interface will be initialised -->
+ * calling of interface method won't be done here
+ */
+ private var trackingScanInterface: TrackingScanInterface? = null
+
lateinit var e2eeDialogPresenter: E2EEDialogPresenter
private set
@@ -263,6 +274,8 @@ open class OCFileListFragment :
"Created ${javaClass.simpleName}: folder=${currentFile?.remotePath}, " +
"searchType=$currentSearchType, isSearchFragment=$isSearchFragment"
)
+ // NMC customization will be initialized in nmc/1925-market_tracking
+ trackingScanInterface = TrackingScanInterfaceImpl()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@@ -555,6 +568,10 @@ open class OCFileListFragment :
Intent.createChooser(action, getString(R.string.upload_chooser_title)),
FileDisplayActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS
)
+
+ // track event photo/video/any upload button click
+ AdjustSdkUtils.trackEvent(AdjustSdkUtils.EVENT_TOKEN_FAB_BOTTOM_PHOTO_VIDEO_UPLOAD, preferences)
+ TealiumSdkUtils.trackEvent(TealiumSdkUtils.EVENT_FAB_BOTTOM_PHOTO_VIDEO_UPLOAD, preferences)
}
override fun directCameraUpload() {
@@ -571,6 +588,10 @@ open class OCFileListFragment :
}
showCameraUploadTypeDialog(fileDisplayActivity)
+
+ // NMC: track event for camera upload button click
+ AdjustSdkUtils.trackEvent(AdjustSdkUtils.EVENT_TOKEN_FAB_BOTTOM_CAMERA_UPLOAD, preferences)
+ TealiumSdkUtils.trackEvent(TealiumSdkUtils.EVENT_FAB_BOTTOM_CAMERA_UPLOAD, preferences)
}
private fun showCameraUploadTypeDialog(fileDisplayActivity: FileDisplayActivity) {
@@ -647,6 +668,10 @@ open class OCFileListFragment :
return
}
+ // track event for uploading files button click
+ AdjustSdkUtils.trackEvent(AdjustSdkUtils.EVENT_TOKEN_FAB_BOTTOM_FILE_UPLOAD, preferences)
+ TealiumSdkUtils.trackEvent(TealiumSdkUtils.EVENT_FAB_BOTTOM_FILE_UPLOAD, preferences)
+
UploadFilesActivity.startUploadActivityForResult(
fileActivity,
user,
@@ -695,6 +720,14 @@ open class OCFileListFragment :
//region List item interaction
override fun onShareIconClick(file: OCFile) {
containerActivity?.showDetails(file, SHARING_TAB)
+
+ // track event on click of Share button
+ trackSharingClickEvent()
+ }
+
+ private fun trackSharingClickEvent() {
+ AdjustSdkUtils.trackEvent(AdjustSdkUtils.EVENT_TOKEN_FILE_BROWSER_SHARING, preferences)
+ TealiumSdkUtils.trackEvent(TealiumSdkUtils.EVENT_FILE_BROWSER_SHARING, preferences)
}
override fun showShareDetailView(file: OCFile) {
@@ -944,8 +977,11 @@ open class OCFileListFragment :
private fun handleListAction(@IdRes itemId: Int, checkedFiles: Set): Boolean {
when {
- itemId == R.id.action_send_share_file && checkedFiles.size == SINGLE_SELECTION ->
+ itemId == R.id.action_send_share_file && checkedFiles.size == SINGLE_SELECTION -> {
containerActivity?.showDetails(checkedFiles.first(), SHARING_TAB)
+ // track event on click of Share button
+ trackSharingClickEvent()
+ }
itemId == R.id.action_see_details && checkedFiles.size == SINGLE_SELECTION ->
showDetailsAndHideSortGroup(checkedFiles.first())
@@ -975,6 +1011,8 @@ open class OCFileListFragment :
showDetails(file)
showSortListGroup(false)
}
+ // track event on click of Share button
+ trackSharingClickEvent()
}
private fun startMoveOrCopy(checkedFiles: Set) {
diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/autoUpload/AutoUploadFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/autoUpload/AutoUploadFragment.kt
index a83065469604..642b74b1df82 100644
--- a/app/src/main/java/com/owncloud/android/ui/fragment/autoUpload/AutoUploadFragment.kt
+++ b/app/src/main/java/com/owncloud/android/ui/fragment/autoUpload/AutoUploadFragment.kt
@@ -22,6 +22,7 @@ import com.nextcloud.client.core.Clock
import com.nextcloud.client.device.PowerManagementService
import com.nextcloud.client.jobs.BackgroundJobManager
import com.nextcloud.client.network.ConnectivityService
+import com.nextcloud.client.preferences.AppPreferences
import com.nextcloud.ui.component.UploadWarningCard
import com.nextcloud.utils.extensions.getTypedActivity
import com.nextcloud.utils.extensions.setVisibleIf
@@ -63,6 +64,8 @@ class AutoUploadFragment :
@Inject lateinit var syncedFolderProvider: SyncedFolderProvider
+ @Inject lateinit var preferences: AppPreferences
+
@Inject lateinit var userAccountManager: UserAccountManager
@Inject lateinit var backgroundJobManager: BackgroundJobManager
@@ -188,6 +191,7 @@ class AutoUploadFragment :
persistence,
dialogs,
backgroundJobManager,
+ preferences = preferences,
getAdapter = { adapter },
onItemVisibilityChanged = { emptyContent?.checkAndShowEmptyListContent() }
)
diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/autoUpload/handler/AutoUploadClickHandler.kt b/app/src/main/java/com/owncloud/android/ui/fragment/autoUpload/handler/AutoUploadClickHandler.kt
index d6f32116f547..a06d9d9f03d3 100644
--- a/app/src/main/java/com/owncloud/android/ui/fragment/autoUpload/handler/AutoUploadClickHandler.kt
+++ b/app/src/main/java/com/owncloud/android/ui/fragment/autoUpload/handler/AutoUploadClickHandler.kt
@@ -13,6 +13,9 @@ import androidx.lifecycle.lifecycleScope
import com.nextcloud.client.account.User
import com.nextcloud.client.jobs.BackgroundJobManager
import com.nextcloud.client.jobs.upload.FileUploadHelper
+import com.nextcloud.client.preferences.AppPreferences
+import com.nmc.android.marketTracking.AdjustSdkUtils
+import com.nmc.android.marketTracking.TealiumSdkUtils
import com.owncloud.android.datamodel.MediaFolderType
import com.owncloud.android.datamodel.SyncedFolder
import com.owncloud.android.datamodel.SyncedFolderDisplayItem
@@ -34,6 +37,7 @@ class AutoUploadClickHandler(
private val persistence: AutoUploadPersistence,
private val dialogs: AutoUploadDialogs,
private val backgroundJobManager: BackgroundJobManager,
+ private val preferences: AppPreferences,
private val getAdapter: () -> SyncedFolderAdapter,
private val onItemVisibilityChanged: () -> Unit
) : SyncedFolderAdapter.ClickListener {
@@ -69,6 +73,9 @@ class AutoUploadClickHandler(
fragment.lifecycleScope.launch(Dispatchers.IO) {
fileUploadHelper.removeEntityFromUploadEntities(item.id)
}
+
+ // NMC: track event when user enable/disable auto upload on/off
+ trackAutoUploadEvent(item.isEnabled)
}
override fun onSyncFolderSettingsClick(section: Int, syncedFolderDisplayItem: SyncedFolderDisplayItem?) {
@@ -107,6 +114,22 @@ class AutoUploadClickHandler(
if (isSaved && syncedFolder.isEnabled) {
dialogs.showBatteryOptimizationDialogIfNeeded()
}
+
+ // NMC: track event when user enable/disable auto upload on/off
+ trackAutoUploadEvent(syncedFolder.isEnabled)
+ }
+
+ private fun trackAutoUploadEvent(enabled: Boolean) {
+ AdjustSdkUtils.trackEvent(
+ if (enabled) AdjustSdkUtils.EVENT_TOKEN_SETTINGS_AUTO_UPLOAD_ON
+ else AdjustSdkUtils.EVENT_TOKEN_SETTINGS_AUTO_UPLOAD_OFF,
+ preferences
+ )
+ TealiumSdkUtils.trackEvent(
+ if (enabled) TealiumSdkUtils.EVENT_SETTINGS_AUTO_UPLOAD_ON
+ else TealiumSdkUtils.EVENT_SETTINGS_AUTO_UPLOAD_OFF,
+ preferences
+ )
}
fun onDeleteAutoUploadFolderPreference(syncedFolder: SyncedFolderParcelable?) {
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 1374fb3d4f05..27ec6466f6ae 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -305,8 +305,9 @@
Tägliche Sicherung
Zu sichernde Daten
Zugangsdaten falsch
- Konto entfernen
+ Benutzer abmelden
Einträge löschen
+ Achtung! Alles wird in den Ausgangszustand zurückgesetzt. Fortfahren?
Link löschen
Auswahl aufheben
Ziel-Dateiname
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 02ad7b2f9b0c..6799c3e8ffe4 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -299,7 +299,8 @@
Request account deletion
Request deletion
Request permanent deletion of account by service provider
- Remove account
+ Logout user
+ Attention! Will be reset to initial state. Continue?
Avatar
Active user
Upload from…
diff --git a/gradle.properties b/gradle.properties
index 91f3dedc1c10..efedea15ddec 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -8,7 +8,7 @@ NC_TEST_SERVER_PASSWORD=test
android.useAndroidX=true
android.nonTransitiveRClass=true
#android.debug.obsoleteApi=true
-
+ADJUST_APP_TOKEN="54qd7rraqav4"
# JVM arguments to optimize heap usage, enable heap dump on out-of-memory errors, and set the file encoding
org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index fb482855de0b..390edafa7948 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -50,6 +50,9 @@ kotlinxSerializationJson = "1.12.0"
ksp = "2.3.12"
leakcanary = "2.14"
legacySupportV4Version = "1.0.0"
+adjustAndroidVersion = "5.1.0"
+installreferrerVersion = "2.2"
+tealiumlibraryVersion = "5.8.0"
libraryVersion = "1.3.0"
lifecycleViewmodelKtxVersion = "2.11.0"
loaderviewlibraryVersion = "3.0.0"
@@ -68,6 +71,7 @@ playServicesBaseVersion = "18.11.1"
prismVersion = "2.0.0"
qrcodescannerVersion = "0.1.2.4"
reviewKtxVersion = "2.0.2"
+playServicesAdsIdentifierVersion = "18.0.1"
roomVersion = "2.8.5"
screengrabVersion = "2.1.1"
sectionedRecyclerviewVersion = "0.6.1"
@@ -134,6 +138,7 @@ firebase-messaging = { module = "com.google.firebase:firebase-messaging", versio
gson = { module = "com.google.code.gson:gson", version.ref = "gsonVersion" }
html = { module = "io.noties.markwon:html", version.ref = "markwonVersion" }
ical4j = { module = "org.mnode.ical4j:ical4j", version.ref = "ical4jVersion" }
+play-services-ads-identifier = { module = "com.google.android.gms:play-services-ads-identifier", version.ref = "playServicesAdsIdentifierVersion" }
jackrabbit-webdav = { module = "org.apache.jackrabbit:jackrabbit-webdav", version.ref = "jackrabbitWebdavVersion" }
json = { module = "org.json:json", version.ref = "jsonVersion" }
juniversalchardet = { module = "com.github.albfernandez:juniversalchardet", version.ref = "juniversalchardetVersion" }
@@ -167,6 +172,11 @@ lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", v
lifecycle-service = { module = "androidx.lifecycle:lifecycle-service", version.ref = "lifecycleViewmodelKtxVersion" }
lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtxVersion" }
+# NMC Marketing
+adjust-android = { module = "com.adjust.sdk:adjust-android", version.ref = "adjustAndroidVersion" }
+installreferrer = { module = "com.android.installreferrer:installreferrer", version.ref = "installreferrerVersion" }
+tealium-library = { module = "com.tealium:library", version.ref = "tealiumlibraryVersion" }
+
# ksp
ksp = { module = "com.github.bumptech.glide:ksp", version.ref = "glide" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 26e4b55708b4..33678753a06c 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -37,6 +37,8 @@ dependencyResolutionManagement {
}
}
mavenCentral()
+ // NMC Customization: tealium
+ maven("https://maven.tealiumiq.com/android/releases/")
maven("https://jitpack.io")
}
}