From d82be3a92edc5f1609d6a22dc26419551e5324ae Mon Sep 17 00:00:00 2001 From: A117870935 Date: Thu, 18 May 2023 18:03:56 +0530 Subject: [PATCH] Tealium, Adjust and MoEngage SDKs added from following branches: feature/NMCLOUD-339 feature/NMCLOUD-177 feature/NMCLOUD-428 --- app/build.gradle | 28 +++++ app/src/main/AndroidManifest.xml | 11 ++ .../nextcloud/client/di/ActivityInjector.kt | 7 +- .../client/preferences/AppPreferences.java | 18 +++ .../preferences/AppPreferencesImpl.java | 25 ++++ .../android/marketTracking/AdjustSdkUtils.kt | 67 +++++++++++ .../marketTracking/MoEngageSdkUtils.kt | 21 ++++ .../android/marketTracking/TealiumSdkUtils.kt | 107 ++++++++++++++++++ .../marketTracking/TrackingScanInterface.kt | 14 +++ .../TrackingScanInterfaceImpl.kt | 18 +++ .../com/nmc/android/ui/PrivacyUserAction.kt | 9 ++ .../java/com/owncloud/android/MainApp.java | 15 +++ .../authentication/AuthenticatorActivity.java | 13 +++ .../ui/activity/FileDisplayActivity.java | 4 + .../android/ui/activity/SettingsActivity.java | 8 ++ .../ui/activity/SyncedFoldersActivity.kt | 13 +++ .../AccountRemovalConfirmationDialog.kt | 16 ++- .../ui/fragment/FileDetailFragment.java | 3 + .../fragment/FileDetailSharingFragment.java | 8 ++ .../fragment/OCFileListBottomSheetDialog.java | 8 ++ .../ui/fragment/OCFileListFragment.java | 39 +++++++ gradle.properties | 2 + 22 files changed, 448 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/com/nmc/android/marketTracking/AdjustSdkUtils.kt create mode 100644 app/src/main/java/com/nmc/android/marketTracking/MoEngageSdkUtils.kt create mode 100644 app/src/main/java/com/nmc/android/marketTracking/TealiumSdkUtils.kt create mode 100644 app/src/main/java/com/nmc/android/marketTracking/TrackingScanInterface.kt create mode 100644 app/src/main/java/com/nmc/android/marketTracking/TrackingScanInterfaceImpl.kt create mode 100644 app/src/main/java/com/nmc/android/ui/PrivacyUserAction.kt diff --git a/app/build.gradle b/app/build.gradle index 1227b2cf78ad..c908d5a89904 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,6 +13,16 @@ buildscript { classpath "org.jacoco:org.jacoco.report:$jacoco_version" classpath "org.jacoco:org.jacoco.agent:$jacoco_version" } + + //NMC Customization + allprojects { + repositories { + jcenter() + maven { + url "https://maven.tealiumiq.com/android/releases/" + } + } + } } plugins { @@ -90,6 +100,10 @@ android { buildConfigField 'boolean', 'CI', ciBuild.toString() buildConfigField 'boolean', 'RUNTIME_PERF_ANALYSIS', perfAnalysis.toString() + //NMC customization + buildConfigField "String", "ADJUST_APP_TOKEN", "${ADJUST_APP_TOKEN}" + buildConfigField "String", "MOENGAGE_APP_ID", "${MOENGAGE_APP_ID}" + javaCompileOptions { annotationProcessorOptions { arguments += ["room.schemaLocation": "$projectDir/schemas".toString()] @@ -383,6 +397,20 @@ dependencies { ksp "androidx.room:room-compiler:$roomVersion" androidTestImplementation "androidx.room:room-testing:$roomVersion" + //Adjust SDK --> https://github.com/adjust/android_sdk + implementation 'com.adjust.sdk:adjust-android:4.28.1' + implementation 'com.android.installreferrer:installreferrer:2.2' + //google play services identifier required for Adjust SDK + implementation 'com.google.android.gms:play-services-ads-identifier:17.0.0' + + //tealium sdk + implementation 'com.tealium:library:5.8.0' + + //MoEngage SDK + implementation 'com.moengage:moe-android-sdk:11.3.01' + //lifecycle required for MoEngage SDK + implementation 'androidx.lifecycle:lifecycle-process:2.2.0' + implementation "io.coil-kt:coil:2.4.0" // splash screen dependency ref: https://developer.android.com/develop/ui/views/launch/splash-screen/migrate diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 349d5da8a935..b7d588006e17 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -489,6 +489,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); + MoEngageSdkUtils.initMoEngageSDK(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.java b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java index 9a3b9a1ab088..a7878d70fcd9 100644 --- a/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java +++ b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java @@ -86,6 +86,8 @@ import com.nextcloud.client.onboarding.OnboardingService; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.java.util.Optional; +import com.nmc.android.marketTracking.AdjustSdkUtils; +import com.nmc.android.marketTracking.TealiumSdkUtils; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.databinding.AccountSetupBinding; @@ -1210,6 +1212,10 @@ public void onAuthenticatorTaskCallback(RemoteOperationResult result) } private void endSuccess() { + //track successful login event + AdjustSdkUtils.trackEvent(AdjustSdkUtils.EVENT_TOKEN_SUCCESSFUL_LOGIN, preferences); + TealiumSdkUtils.trackEvent(TealiumSdkUtils.EVENT_SUCCESSFUL_LOGIN, preferences); + if (onlyAdd) { finish(); } else { @@ -1546,4 +1552,11 @@ public void onSavedCertificate() { public void onFailedSavingCertificate() { DisplayUtils.showSnackMessage(this, R.string.ssl_validator_not_saved); } + + @Override + protected void onStart() { + super.onStart(); + //track screen view when activity is visible + TealiumSdkUtils.trackView(TealiumSdkUtils.SCREEN_VIEW_LOGIN, preferences); + } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 16478cd5b628..3f59d4165e05 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -70,6 +70,7 @@ import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.client.utils.IntentUtil; +import com.nmc.android.marketTracking.TealiumSdkUtils; import com.nextcloud.java.util.Optional; import com.nextcloud.utils.view.FastScrollUtils; import com.owncloud.android.MainApp; @@ -2429,6 +2430,9 @@ public void onStart() { EventBus.getDefault().post(new TokenPushEvent()); checkForNewDevVersionNecessary(getApplicationContext()); + + //track screen view when activity is visible + TealiumSdkUtils.trackView(TealiumSdkUtils.SCREEN_VIEW_FILE_BROWSER, preferences); } @Override 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 da23f3168a8c..1389ddf73bb3 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 @@ -58,6 +58,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.owncloud.android.BuildConfig; @@ -1058,6 +1059,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/activity/SyncedFoldersActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt index 3b5b5e313dda..32a85ad7dd47 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt @@ -45,6 +45,8 @@ import com.nextcloud.client.jobs.MediaFoldersDetectionWork import com.nextcloud.client.jobs.NotificationWork import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.client.preferences.SubFolderRule +import com.nmc.android.marketTracking.AdjustSdkUtils +import com.nmc.android.marketTracking.TealiumSdkUtils import com.owncloud.android.BuildConfig import com.owncloud.android.MainApp import com.owncloud.android.R @@ -582,6 +584,9 @@ class SyncedFoldersActivity : backgroundJobManager.startImmediateFilesSyncJob(skipCustomFolders = false, overridePowerSaving = false) showBatteryOptimizationInfo() } + + //track event when user enable/disable auto upload on/off + trackAutoUploadEvent(syncedFolderDisplayItem.isEnabled) } override fun onSyncFolderSettingsClick(section: Int, syncedFolderDisplayItem: SyncedFolderDisplayItem) { @@ -695,6 +700,14 @@ class SyncedFoldersActivity : if (syncedFolder.isEnabled) { showBatteryOptimizationInfo() } + + //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) } private fun saveOrUpdateSyncedFolder(item: SyncedFolderDisplayItem) { diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.kt index a32e818abe43..442366400cc8 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.kt @@ -30,6 +30,9 @@ import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.nextcloud.client.account.User import com.nextcloud.client.di.Injectable +import com.nextcloud.client.preferences.AppPreferences +import com.nmc.android.marketTracking.AdjustSdkUtils +import com.nmc.android.marketTracking.TealiumSdkUtils import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.R import com.owncloud.android.utils.theme.ViewThemeUtils @@ -44,6 +47,10 @@ class AccountRemovalConfirmationDialog : DialogFragment(), Injectable { @Inject var viewThemeUtils: ViewThemeUtils? = null + @JvmField + @Inject + var appPreferences: AppPreferences? = null + private var user: User? = null override fun onCreate(savedInstanceState: Bundle?) { @@ -77,10 +84,11 @@ class AccountRemovalConfirmationDialog : DialogFragment(), Injectable { .setMessage(resources.getString(R.string.delete_account_warning, user!!.accountName)) .setIcon(R.drawable.ic_warning) .setPositiveButton(R.string.common_ok) { _: DialogInterface?, _: Int -> - backgroundJobManager?.startAccountRemovalJob( - user!!.accountName, - false - ) + // 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) } .setNegativeButton(R.string.common_cancel, null) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 8396ceb3e861..141ac8dc626b 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -50,6 +50,7 @@ import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.ui.fileactions.FileActionsBottomSheet; import com.nextcloud.utils.MenuUtils; +import com.nmc.android.marketTracking.TealiumSdkUtils; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.databinding.FileDetailsFragmentBinding; @@ -362,6 +363,8 @@ public void onStart() { super.onStart(); listenForTransferProgress(); EventBus.getDefault().register(this); + //track screen view when fragment is visible + TealiumSdkUtils.trackView(TealiumSdkUtils.SCREEN_VIEW_SHARING, preferences); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index cde91289f708..ac39d3814cab 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -56,6 +56,9 @@ import com.owncloud.android.ui.adapter.ShareeListAdapter; import com.owncloud.android.ui.adapter.ShareeListAdapterListener; import com.owncloud.android.ui.asynctasks.RetrieveHoverCardAsyncTask; +import com.nextcloud.client.preferences.AppPreferences; +import com.nmc.android.marketTracking.AdjustSdkUtils; +import com.nmc.android.marketTracking.TealiumSdkUtils; import com.owncloud.android.ui.dialog.SharePasswordDialogFragment; import com.owncloud.android.ui.fragment.util.FileDetailSharingFragmentHelper; import com.owncloud.android.ui.helpers.FileOperationsHelper; @@ -98,6 +101,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda @Inject UserAccountManager accountManager; @Inject ClientFactory clientFactory; @Inject ViewThemeUtils viewThemeUtils; + @Inject AppPreferences appPreferences; public static FileDetailSharingFragment newInstance(OCFile file, User user) { FileDetailSharingFragment fragment = new FileDetailSharingFragment(); @@ -280,6 +284,10 @@ public void createPublicShareLink() { // create without password if not enforced by server or we don't know if enforced; 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 diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java index 95701987ab50..323244f04046 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java @@ -29,7 +29,9 @@ import com.nextcloud.client.device.DeviceInfo; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.documentscan.AppScanOptionalFeature; +import com.nextcloud.client.preferences.AppPreferencesImpl; import com.nextcloud.utils.EditorUtils; +import com.nmc.android.marketTracking.TealiumSdkUtils; import com.owncloud.android.R; import com.owncloud.android.databinding.FileListActionsBottomSheetCreatorBinding; import com.owncloud.android.databinding.FileListActionsBottomSheetFragmentBinding; @@ -170,6 +172,12 @@ protected void onCreate(Bundle savedInstanceState) { } setupClickListener(); + + //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 void setupClickListener() { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 26f2ac3ecdce..76d5f3f6d113 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -67,7 +67,11 @@ import com.nextcloud.ui.fileactions.FileActionsBottomSheet; import com.nextcloud.utils.EditorUtils; import com.nextcloud.utils.ShortcutUtil; +import com.nmc.android.marketTracking.TrackingScanInterface; import com.nextcloud.utils.view.FastScrollUtils; +import com.nmc.android.marketTracking.AdjustSdkUtils; +import com.nmc.android.marketTracking.TrackingScanInterfaceImpl; +import com.nmc.android.marketTracking.TealiumSdkUtils; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.datamodel.ArbitraryDataProvider; @@ -235,6 +239,13 @@ public class OCFileListFragment extends ExtendedListFragment implements @Inject 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 TrackingScanInterface trackingScanInterface; + protected enum MenuItemAddRemove { DO_NOTHING, REMOVE_SORT, @@ -259,6 +270,9 @@ public void onCreate(Bundle savedInstanceState) { } searchFragment = currentSearchType != null && isSearchEventSet(searchEvent); + + //NMC customization will be initialised in nmc/1925-market_tracking + trackingScanInterface = new TrackingScanInterfaceImpl(); } @Override @@ -521,6 +535,10 @@ public void uploadFromApp() { 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 @@ -533,6 +551,10 @@ public void directCameraUpload() { } else { DisplayUtils.showSnackMessage(getView(), getString(R.string.error_starting_direct_camera_upload)); } + + //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); } @Override @@ -563,6 +585,10 @@ public void uploadFiles() { FileDisplayActivity.REQUEST_CODE__SELECT_FILES_FROM_FILE_SYSTEM, getCurrentFile().isEncrypted() ); + + //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); } @Override @@ -591,6 +617,14 @@ public void onShareIconClick(OCFile file) { mContainerActivity.getFileOperationsHelper().sendShareFile(file); }); } + + //track event on click of Share button + trackSharingClickEvent(); + } + + private void trackSharingClickEvent() { + AdjustSdkUtils.trackEvent(AdjustSdkUtils.EVENT_TOKEN_FILE_BROWSER_SHARING, preferences); + TealiumSdkUtils.trackEvent(TealiumSdkUtils.EVENT_FILE_BROWSER_SHARING, preferences); } @Override @@ -1159,6 +1193,8 @@ public boolean onFileActionChosen(@IdRes final int itemId, Set checkedFi if (itemId == R.id.action_send_share_file) { mContainerActivity.getFileOperationsHelper().sendShareFile(singleFile); + //track event on click of Share button + trackSharingClickEvent(); return true; } else if (itemId == R.id.action_open_file_with) { mContainerActivity.getFileOperationsHelper().openFile(singleFile); @@ -1189,6 +1225,9 @@ public boolean onFileActionChosen(@IdRes final int itemId, Set checkedFi mContainerActivity.showDetails(singleFile); mContainerActivity.showSortListGroup(false); + + //track event on click of Share button + trackSharingClickEvent(); return true; } else if (itemId == R.id.action_set_as_wallpaper) { mContainerActivity.getFileOperationsHelper().setPictureAs(singleFile, getView()); diff --git a/gradle.properties b/gradle.properties index 85bc2ba7da37..add468064c4c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,6 +8,8 @@ android.defaults.buildfeatures.buildconfig=true android.nonTransitiveRClass=false android.nonFinalResIds=false #android.debug.obsoleteApi=true +ADJUST_APP_TOKEN="54qd7rraqav4" +MOENGAGE_APP_ID="XGJ4VU4OZ7HFU7EV5WTATM9K" # Minimum max heap space to get reliable builds org.gradle.jvmargs=-Xmx1g