SEPARATE MODULE CREATION (#7)

This commit is contained in:
Aman S
2023-07-19 15:17:10 +05:30
committed by Shivam Goyal
parent d9ffc84974
commit 029f88c8d4
18 changed files with 525 additions and 252 deletions

2
.idea/kotlinc.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.7.20" />
<option name="version" value="1.6.21" />
</component>
</project>

1
.idea/misc.xml generated
View File

@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">

View File

@@ -10,7 +10,8 @@ package com.navi.alfred
import android.os.Build
import android.provider.Settings
import android.text.TextUtils
import com.navi.alfred.utils.*
import com.navi.alfred.utils.AlfredConstants
import com.navi.alfred.utils.getCarrierName
import java.util.*
data class AlfredConfig(
private var appVersionCode: String = "",
@@ -39,13 +40,17 @@ data class AlfredConfig(
private var cpuEnableStatus: Boolean = false,
private var memoryEnableStatus: Boolean = false,
private var metricsApiEnableStatus: Boolean = false,
private var apiResponseEnableStatus:Boolean=false,
private var apiRequestEnableStatus:Boolean=false,
private var enabledApiPath: List<String>? = null,
var batteryPercentageBeforeEventStart: Float? = null,
private var disableScreenList: List<String>? = null,
private var disableModuleList: List<String>? = null,
private var snapshotPerSecond: Int = 1,
private var enableAlfred: Boolean = false,
private var firebaseControlledCruise: Boolean = false,
private var disableChucker:Boolean=true
private var disableDialogScreenShot: Boolean = false,
private var zipFileName: String? = null,
private var disableAlfredLogs: Boolean = true
) {
@@ -96,11 +101,6 @@ data class AlfredConfig(
fun setAlfredStatus(enable: Boolean) {
this.enableAlfred = enable
}
fun getFirebaseControlledCruise(): Boolean = this.firebaseControlledCruise
fun setFirebaseControlledCruise(firebaseControlledCruise: Boolean) {
this.firebaseControlledCruise = firebaseControlledCruise
}
fun setEnableRecordingStatus(enableRecording: Boolean) {
this.enableRecording = enableRecording
@@ -133,10 +133,10 @@ data class AlfredConfig(
fun getNetworkCarrier(): String? = getCarrierName(AlfredManager.applicationContext)
fun getNetworkType(): String = getNetworkType(AlfredManager.applicationContext)
fun getNetworkType(): String = com.navi.alfred.utils.getNetworkType(AlfredManager.applicationContext)
fun getBatteryPercentage(): Float =
getBatteryPercentageForDevice(AlfredManager.applicationContext)
com.navi.alfred.utils.getBatteryPercentage(AlfredManager.applicationContext)
fun getUserId(): String? = userId
@@ -173,12 +173,12 @@ data class AlfredConfig(
this.batteryPercentageBeforeEventStart = getBatteryPercentage()
}
fun getCpuUsage(): Float = getCpuUsageForDevice()
fun getCpuUsage(): Float = getCpuUsage()
fun getMemoryUsage(): Float = getMemoryUsageForDevice()
fun getMemoryUsage(): Float = getMemoryUsage()
fun getStorageUsage(): Float {
val (totalSize, freeSize) = getStorageUsageForDevice(context = AlfredManager.applicationContext)
val (totalSize, freeSize) = com.navi.alfred.utils.getStorageUsage(context = AlfredManager.applicationContext)
return (totalSize - freeSize).toFloat()
}
@@ -229,5 +229,38 @@ data class AlfredConfig(
}
fun getMetricsApiEnableStatus(): Boolean = this.metricsApiEnableStatus
fun getDisableChuckerStatus(): Boolean = this.disableChucker
fun setApiResponseEnableStatus(status: Boolean) {
this.apiResponseEnableStatus = status
}
fun getApiResponseEnableStatus(): Boolean = this.apiResponseEnableStatus
fun setApiRequestEnableStatus(status: Boolean) {
this.apiRequestEnableStatus = status
}
fun getApiRequestEnableStatus(): Boolean = this.apiRequestEnableStatus
fun setEnabledApiPath(enabledApiPath: List<String>?) {
this.enabledApiPath = enabledApiPath
}
fun getEnabledApiPath():Set<String>? = this.enabledApiPath?.toSet()
fun setDisableDialogScreenShot(status: Boolean){
this.disableDialogScreenShot=status
}
fun getDisableDialogScreenShot(): Boolean {
return this.disableDialogScreenShot
}
fun setZipFileName(zipFileName: String) {
this.zipFileName = zipFileName
}
fun getZipFileName(): String? = this.zipFileName
fun clearZipFileName() {
this.zipFileName = ""
}
fun getDisableAlfredLogsStatus(): Boolean = this.disableAlfredLogs
}

View File

@@ -11,6 +11,7 @@ import android.app.Dialog
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.util.Log
import android.view.KeyEvent.ACTION_DOWN
import android.view.KeyEvent.ACTION_UP
import android.view.MotionEvent
@@ -20,7 +21,6 @@ import androidx.annotation.WorkerThread
import androidx.work.*
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.navi.alfred.utils.ScreenShotStorageHelper
import com.navi.alfred.db.AlfredDatabase
import com.navi.alfred.db.AlfredDatabaseHelper
import com.navi.alfred.db.dao.ApiMetricDao
@@ -31,15 +31,38 @@ import com.navi.alfred.db.model.ApiMetricHelper
import com.navi.alfred.db.model.ScreenShotPathHelper
import com.navi.alfred.db.model.ZipDetailsHelper
import com.navi.alfred.dispatcher.AlfredDispatcher
import com.navi.alfred.model.*
import com.navi.alfred.model.AnalyticsRequest
import com.navi.alfred.model.BaseAttribute
import com.navi.alfred.model.DeviceAttributes
import com.navi.alfred.model.EventAttribute
import com.navi.alfred.model.EventMetricRequest
import com.navi.alfred.model.MetricAttribute
import com.navi.alfred.model.NaviMotionEvent
import com.navi.alfred.model.SessionEventAttribute
import com.navi.alfred.model.SessionRequest
import com.navi.alfred.model.WorkManagerFailureInputData
import com.navi.alfred.network.AlfredNetworkRepository
import com.navi.alfred.network.AlfredRetrofitProvider
import com.navi.alfred.network.model.CruiseResponse
import com.navi.alfred.utils.*
import com.navi.alfred.utils.AlfredConstants
import com.navi.alfred.utils.AlfredConstants.ALFRED
import com.navi.alfred.utils.AlfredConstants.API_METRICS
import com.navi.alfred.utils.AlfredConstants.CODE_API_BAD_REQUEST
import com.navi.alfred.utils.AlfredConstants.CODE_API_SUCCESS
import com.navi.alfred.utils.AlfredConstants.THIRD_PARTY_MODULE
import com.navi.alfred.utils.AlfredConstants.X_TARGET
import com.navi.alfred.utils.AlfredConstants.ZIP_FILE_EXTENSION
import com.navi.alfred.utils.ScreenShotStorageHelper
import com.navi.alfred.utils.captureScreen
import com.navi.alfred.utils.captureScreenshotOfCustomView
import com.navi.alfred.utils.checkFileExists
import com.navi.alfred.utils.clearScreenShot
import com.navi.alfred.utils.combineScreenshots
import com.navi.alfred.utils.createBitmapForView
import com.navi.alfred.utils.getTouchEvent
import com.navi.alfred.utils.insertScreenShotPathInDb
import com.navi.alfred.utils.log
import com.navi.alfred.utils.zip
import com.navi.alfred.worker.AddEventTask
import com.navi.alfred.worker.AddMetricTask
import com.navi.alfred.worker.UploadFileWorker
@@ -50,7 +73,6 @@ import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.Response
import okio.Buffer
import java.io.File
import java.lang.reflect.Type
import java.util.*
@@ -63,7 +85,7 @@ object AlfredManager {
lateinit var config: AlfredConfig
lateinit var applicationContext: Context
private var previousTouchEvent: NaviMotionEvent = NaviMotionEvent()
private val mutex = Mutex()
val mutex = Mutex()
private val coroutineDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
private val repository = AlfredNetworkRepository()
private val completableJob = Job()
@@ -75,7 +97,6 @@ object AlfredManager {
private const val imageThreshHoldValue: Int = 60
private const val imageSecondThreshHoldValue: Int = 100
private var screenShotCaptureDelay: Long = 1000L
private var isAppInBackground: Boolean = false
private var hasRecordingStarted: Boolean = false
var dialog: Dialog? = null
private var timer: Timer? = null
@@ -83,23 +104,22 @@ object AlfredManager {
private var viewLayoutDelay: Long = 1000
private var currentScreenName: String? = null
private var currentModuleName: String? = null
private var sessionIdForCrash: String? = null
private var sessionStartRecordingTimeForCrash: Long? = null
private var eventStartRecordingTimeForCrash: Long? = null
val workFailureData: MutableList<WorkManagerFailureInputData> = mutableListOf()
private var retryCount: Int = 0
private lateinit var zipFileDetails: List<ZipDetailsHelper>
private val exceptionHandler = CoroutineExceptionHandler { _, exception ->
private val exceptionHandler = CoroutineExceptionHandler { _, _ ->
}
private val coroutineScope = CoroutineScope(Dispatchers.IO + completableJob + exceptionHandler)
fun init(config: AlfredConfig, context: Context) {
this.config = config
this.applicationContext = context
AlfredManager.config = config
applicationContext = context
AlfredRetrofitProvider.init(applicationContext)
startSyncEvents(context)
alfredDataBase = AlfredDatabaseHelper.getAnalyticsDatabase(applicationContext)
this.screenShotDao = alfredDataBase.screenShotDao()
this.zipDetailsDao = alfredDataBase.zipDetailsDao()
this.apiMetricDao = alfredDataBase.apiMetricDao()
screenShotDao = alfredDataBase.screenShotDao()
zipDetailsDao = alfredDataBase.zipDetailsDao()
apiMetricDao = alfredDataBase.apiMetricDao()
}
fun startRecording(
@@ -188,15 +208,16 @@ object AlfredManager {
}
private suspend fun checkToStartZipUpload() {
val zipFileName =
config.getAlfredSessionId() + config.getSessionStartRecordingTime().toString()
if (checkFileExists(
zipFileName, applicationContext
) != null
) {
if (!hasUploadFlowStarted) {
hasUploadFlowStarted = true
getPreSignedUrl(zipFileName)
val zipFileName = config.getZipFileName().toString()
if (zipFileName.isNotEmpty()) {
if (checkFileExists(
zipFileName, applicationContext
) != null
) {
if (!hasUploadFlowStarted) {
hasUploadFlowStarted = true
getPreSignedUrl(zipFileName)
}
}
}
}
@@ -209,6 +230,9 @@ object AlfredManager {
rootBmp: Bitmap? = null,
moduleName: String? = null
) {
if(config.getDisableDialogScreenShot()){
return
}
val bottomSheetView = dialog?.window?.decorView?.rootView
if (bottomSheetView != null) {
val bottomSheetCanvasForBitmap = createBitmapForView(bottomSheetView)
@@ -249,16 +273,17 @@ object AlfredManager {
private fun checkDbBeforeStartRecording() {
coroutineScope.launch(Dispatchers.IO) {
if (screenShotDao.getScreenShotCount() > 0) {
clearScreenShot(screenShotDao.fetchAllScreenShotsPath())
screenShotDao.deleteAllScreenShot()
}
if (zipDetailsDao.getZipFilesDetailsCount() > 0) {
zipFileDetails = zipDetailsDao.fetchAllZipFilesDetails()
zipFileDetails.forEachIndexed { index, DumpZipDetailsHelper ->
val zipFileName =
DumpZipDetailsHelper.alfredSessionId + DumpZipDetailsHelper.sessionStartRecordingTime.toString()
if (checkFileExists(fileName = zipFileName, applicationContext) != null) {
getPreSignedUrl(zipFileName, true, index)
if (checkFileExists(
fileName = DumpZipDetailsHelper.zipFileName,
applicationContext
) != null
) {
getPreSignedUrl(DumpZipDetailsHelper.zipFileName, true, index)
} else {
zipDetailsDao.deleteZipFileDetail(DumpZipDetailsHelper.id)
}
@@ -287,8 +312,12 @@ object AlfredManager {
config.getDeviceId()
)
if (response.isSuccessful && response.code() == CODE_API_SUCCESS) {
response.body()?.let { cruiseResponse ->
setCruiseConfig(cruiseResponse)
try {
response.body()?.let { cruiseResponse ->
setCruiseConfig(cruiseResponse)
}
} catch (e: Exception) {
e.log()
}
}
}
@@ -334,6 +363,15 @@ object AlfredManager {
metricsConfig.disableApiPerformance?.let { api_monitor_status ->
config.setApiMetricsEnableStatus(!api_monitor_status)
}
metricsConfig.disableApiRequest?.let { api_request_status ->
config.setApiRequestEnableStatus(!api_request_status)
}
metricsConfig.disableApiResponse?.let { api_response_status ->
config.setApiResponseEnableStatus(!api_response_status)
}
metricsConfig.enabledApiPaths.let {enabled_api_path ->
config.setEnabledApiPath(enabled_api_path)
}
}
}
}
@@ -341,35 +379,98 @@ object AlfredManager {
}
private suspend fun getPreSignedUrl(
zipFileName: String, dumpFlow: Boolean = false, index: Int? = null
zipFileName: String,
dumpFlow: Boolean = false,
index: Int? = null,
workManagerFlow: Boolean? = false,
alfredSessionId: String? = null,
eventStartRecordingTime: Long? = null,
sessionStartRecordingTime: Long? = null
) {
config.setAlfredEventId()
val bucketKey = config.getAlfredEventId().plus(ZIP_FILE_EXTENSION)
val response = repository.getPreSignedUrl(bucketKey)
if (response.isSuccessful && response.code() == CODE_API_SUCCESS) {
checkFileExists(
zipFileName, applicationContext
)?.let { file ->
response.body()?.data?.let { uploadFile(file, it, dumpFlow, index) }
}
} else {
if (!dumpFlow) {
hasUploadFlowStarted = false
config.getEventStartRecordingTime()?.let { eventStartRecordingTime ->
insertZipDetailsToDbForDumpingLater(
config.getAlfredSessionId(),
config.getSessionStartRecordingTime(),
eventStartRecordingTime
)
mutex.withLock {
config.setAlfredEventId()
val bucketKey = config.getAlfredEventId().plus(ZIP_FILE_EXTENSION)
val response = repository.getPreSignedUrl(bucketKey)
if (response.isSuccessful && response.code() == CODE_API_SUCCESS) {
if (workManagerFlow == true) {
retryCount = 0
}
checkFileExists(
zipFileName, applicationContext
)?.let { file ->
response.body()?.data?.let { url ->
uploadFile(
file,
url,
dumpFlow,
index,
zipFileName,
workManagerFlow = workManagerFlow,
alfredSessionId = alfredSessionId,
eventStartRecordingTime = eventStartRecordingTime,
sessionStartRecordingTime = sessionStartRecordingTime
)
}
}
} else {
if (!dumpFlow) {
hasUploadFlowStarted = false
config.getEventStartRecordingTime()?.let { eventStartRecordingTime ->
insertZipDetailsToDbForDumpingLater(
config.getAlfredSessionId(),
config.getSessionStartRecordingTime(),
eventStartRecordingTime,
zipFileName
)
}
config.setEventStartRecordingTime(true)
}
if (workManagerFlow == true) {
uploadWorkManagerFailedZip(zipFileName)
} else {
}
config.setEventStartRecordingTime(true)
}
}
}
private fun uploadWorkManagerFailedZip(zipFileName: String) {
retryCount +=1
if (workFailureData.size > 0) {
val inputData = workFailureData[0]
WorkManager.getInstance(applicationContext).cancelWorkById(inputData.id)
if (retryCount <= 3) {
val requestData = Data.Builder()
.putString(AlfredConstants.ALFRED_SESSION_ID, inputData.alfredSessionId)
.putLong(
AlfredConstants.SESSION_START_RECORDING_TIME,
inputData.sessionStartRecordingTime
).putLong(
AlfredConstants.EVENT_START_RECORDING_TIME,
inputData.eventStartRecordingTime
).putString(
AlfredConstants.SCREENSHOT_LIST,
Gson().toJson(inputData.screenShots)
)
.build()
buildWorkManager(requestData)
} else {
insertZipDetailsToDbForDumpingLater(
inputData.alfredSessionId.toString(),
inputData.sessionStartRecordingTime,
inputData.eventStartRecordingTime,
zipFileName
)
}
workFailureData.removeAt(0)
}
}
private fun checkAndInitiateFileUploadWorkManager() {
val screenShotList = screenShotDao.fetchAllScreenShotsPath()
screenShotDao.deleteAllScreenShot()
ScreenShotStorageHelper.clearAll()
hasRecordingStarted = false
config.clearZipFileName()
val requestData = Data.Builder()
.putString(AlfredConstants.ALFRED_SESSION_ID, config.getAlfredSessionId())
.putLong(
@@ -380,6 +481,10 @@ object AlfredManager {
config.getEventStartRecordingTime() ?: 0L
).putString(AlfredConstants.SCREENSHOT_LIST, Gson().toJson(screenShotList))
.build()
buildWorkManager(requestData)
}
private fun buildWorkManager(requestData: Data) {
val constraints = Constraints.Builder().setRequiresBatteryNotLow(false)
.setRequiredNetworkType(NetworkType.CONNECTED).build()
val uniqueWorkName = "YOUR_UNIQUE_WORK_NAME"
@@ -391,7 +496,7 @@ object AlfredManager {
.setInputData(requestData)
.build()
WorkManager.getInstance(applicationContext)
.beginUniqueWork(uniqueWorkName, ExistingWorkPolicy.REPLACE, uniqueWorkRequest)
.beginUniqueWork(uniqueWorkName, ExistingWorkPolicy.KEEP, uniqueWorkRequest)
.enqueue()
} else {
val workRequest = OneTimeWorkRequestBuilder<UploadFileWorker>()
@@ -404,7 +509,15 @@ object AlfredManager {
}
private suspend fun uploadFile(
uploadFile: File, url: String, dumpFlow: Boolean = false, index: Int? = null
uploadFile: File,
url: String,
dumpFlow: Boolean = false,
index: Int? = null,
zipFileName: String,
workManagerFlow: Boolean? = false,
alfredSessionId: String? = null,
eventStartRecordingTime: Long? = null,
sessionStartRecordingTime: Long? = null
) {
val requestBody = uploadFile.asRequestBody("application/zip".toMediaTypeOrNull())
val uploadResponse = repository.uploadZipToS3(
@@ -412,18 +525,30 @@ object AlfredManager {
)
if (uploadResponse.isSuccessful && uploadResponse.code() == CODE_API_SUCCESS) {
uploadFile.delete()
sendAlfredSessionEvent(dumpFlow, index)
if (workManagerFlow == true) {
retryCount = 0
}
sendAlfredSessionEvent(
dumpFlow, index,
alfredSessionId = alfredSessionId,
eventStartRecordingTime = eventStartRecordingTime,
sessionStartRecordingTime = sessionStartRecordingTime
)
} else {
if (!dumpFlow) {
config.getEventStartRecordingTime()?.let { eventStartRecordingTime ->
insertZipDetailsToDbForDumpingLater(
config.getAlfredSessionId(),
config.getSessionStartRecordingTime(),
eventStartRecordingTime
eventStartRecordingTime,
zipFileName
)
}
config.setEventStartRecordingTime(true)
}
if (workManagerFlow == true) {
uploadWorkManagerFailedZip(zipFileName)
}
}
if (!dumpFlow) {
hasUploadFlowStarted = false
@@ -434,42 +559,24 @@ object AlfredManager {
alfredSessionId: String,
sessionStartRecordingTime: Long,
eventStartRecordingTime: Long,
screenShotList: String? = null
zipFileName: String
) {
zipDetailsDao.insert(
data = ZipDetailsHelper(
alfredSessionId = alfredSessionId,
sessionStartRecordingTime = sessionStartRecordingTime,
eventStartRecordingTime = eventStartRecordingTime,
screenShotList = screenShotList
zipFileName = zipFileName
)
)
}
private fun deleteScreenShot() {
private fun deleteScreenShot(imagePathList: List<ScreenShotPathHelper>) {
try {
val screenShotPathList: List<ScreenShotPathHelper> =
if (screenShotDao.getScreenShotCount() >= imageThreshHoldValue) {
screenShotDao.fetchScreenShotsPath(imageThreshHoldValue)
} else {
screenShotDao.fetchAllScreenShotsPath()
}
if (clearScreenShot(screenShotPathList)) {
try {
if (isAppInBackground) {
ScreenShotStorageHelper.clearAll()
screenShotDao.deleteAllScreenShot()
isAppInBackground = false
hasRecordingStarted = false
} else {
val idList = screenShotPathList.map { it.id }
screenShotDao.deleteScreenShot(idList)
ScreenShotStorageHelper.deleteKItems(idList.size)
}
} catch (e: Exception) {
e.log()
}
}
clearScreenShot(imagePathList)
val idList = imagePathList.map { it.id }
screenShotDao.deleteScreenShot(idList)
ScreenShotStorageHelper.deleteKItems(idList.size)
} catch (e: Exception) {
e.log()
}
@@ -496,7 +603,7 @@ object AlfredManager {
AlfredConstants.DEFAULT_INGEST_METRIC_URL,
metricRequestBody = request
)
return if (response.isSuccessful && response.code() == CODE_API_SUCCESS) {
return if ((response.isSuccessful && response.code() == CODE_API_SUCCESS) or (response.code() == CODE_API_BAD_REQUEST)) {
apiMetricDao.deleteApiMetric(metricEventList.map { it.id })
true
} else {
@@ -531,6 +638,31 @@ object AlfredManager {
}
}
fun handleScreenTransitionEvent(
currentScreenName: String?, previousScreenName: String?, screenTransitionDuration: Long
) {
if (config.getAlfredStatus() && config.getMetricsApiEnableStatus()) {
val screenTransitionAttributes: HashMap<String, Any> = hashMapOf()
screenTransitionAttributes.apply {
this[AlfredConstants.CURRENT_SCREEN_NAME] = currentScreenName.orEmpty()
this[AlfredConstants.PREVIOUS_SCREEN_NAME] = previousScreenName.orEmpty()
this[AlfredConstants.LOAD_TIME] = screenTransitionDuration
}
coroutineDispatcher.executor.execute {
val screenTransitionEvent = buildAppPerformanceEvent(
eventName = AlfredConstants.SCREEN_TRANSITION_METRICS,
attribute = screenTransitionAttributes,
eventType = AlfredConstants.SCREEN_TRANSITION_METRICS
)
AlfredDispatcher.addTaskToQueue(
AddMetricTask(
screenTransitionEvent, applicationContext
)
)
}
}
}
suspend fun sendEventsToServer(
applicationContext: Context
@@ -557,7 +689,7 @@ object AlfredManager {
val response = repository.sendEvents(
config.getPostUrl(), request
)
return if (response.isSuccessful && response.code() == CODE_API_SUCCESS) {
return if ((response.isSuccessful && response.code() == CODE_API_SUCCESS) or (response.code() == CODE_API_BAD_REQUEST)) {
analyticsDao.deleteEvents(analyticsEvents.map { it.eventId })
true
} else {
@@ -578,7 +710,12 @@ object AlfredManager {
return false
}
private fun sendAlfredSessionEvent(dumpFlow: Boolean = false, index: Int? = null) {
private fun sendAlfredSessionEvent(
dumpFlow: Boolean = false, index: Int? = null,
alfredSessionId: String? = null,
eventStartRecordingTime: Long? = null,
sessionStartRecordingTime: Long? = null
) {
var request: SessionRequest? = null
if (dumpFlow) {
var clientTs: Long? = null
@@ -590,9 +727,9 @@ object AlfredManager {
sessionTimeStamp = zipFileDetail.sessionStartRecordingTime
sessionId = zipFileDetail.alfredSessionId
} else {
clientTs = eventStartRecordingTimeForCrash
sessionTimeStamp = sessionStartRecordingTimeForCrash
sessionId = sessionIdForCrash
clientTs = eventStartRecordingTime
sessionTimeStamp = sessionStartRecordingTime
sessionId = alfredSessionId
}
request = SessionRequest(
base_attribute = BaseAttribute(
@@ -633,6 +770,13 @@ object AlfredManager {
if (!dumpFlow) {
config.setEventStartRecordingTime(true)
handleDeviceAttributes()
} else {
index?.let { index ->
zipDetailsDao.deleteZipFileDetail(zipFileDetails[index].id)
}
if(workFailureData.size>0){
workFailureData.removeAt(0)
}
}
}
}
@@ -669,8 +813,19 @@ object AlfredManager {
} else {
null
}
var url= request.url.toString().split("?").first()
request.header(ALFRED)?.let {pathParam ->
if(url.contains(pathParam)){
url=url.replace(pathParam,"Path_Param_Value")
request.header(X_TARGET)?.let {xTarget ->
url=xTarget.plus(url)
}
}
}
Log.d("ALFREDAPI","URL$url")
Log.d("ALFREDAPI","RESPONSE BODY${response.message}")
val attributes = hashMapOf<String, Any>().apply {
this[AlfredConstants.URL] = request.url.toString()
this[AlfredConstants.URL] = url
this[AlfredConstants.METHOD] = request.method
this[AlfredConstants.RESPONSE_CODE] = response.code
this[AlfredConstants.ERROR_MESSAGE] = errorMessage.toString()
@@ -680,6 +835,22 @@ object AlfredManager {
this[AlfredConstants.DURATION_IN_MS] = duration.toDouble()
this[AlfredConstants.BYTES_RECEIVED] = byteReceived
this[AlfredConstants.BYTES_SENT] = byteSent
if (config.getApiResponseEnableStatus()) {
if (response.code != CODE_API_SUCCESS || config.getEnabledApiPath()
?.contains(url) == true
) {
Log.d("ALFREDAPI","response${response.body.toString()}")
this[AlfredConstants.RESPONSE_BODY] = response.body.toString()
}
}
if (config.getApiRequestEnableStatus()) {
if (response.code != CODE_API_SUCCESS || config.getEnabledApiPath()
?.contains(url) == true
) {
Log.d("ALFREDAPI","request${request.body.toString()}")
this[AlfredConstants.REQUEST_BODY] = request.body.toString()
}
}
}
val appPerformanceEvent = buildAppPerformanceEvent(
AlfredConstants.API_METRIC_EVENT_NAME, API_METRICS, attributes
@@ -693,18 +864,12 @@ object AlfredManager {
}
}
fun stopRecording(appBackgroundView: View) {
isAppInBackground = true
hasRecordingStarted = false
screenShotTimer?.cancel()
if (config.getFirebaseControlledCruise()) {
deleteScreenShot()
} else {
if (config.getAlfredStatus() && config.getEnableRecordingStatus()) {
if (ScreenShotStorageHelper.images.size > 0) {
startAnrCrashZipUpload(appBackgroundView)
}
if (config.getAlfredStatus() && config.getEnableRecordingStatus()) {
if (ScreenShotStorageHelper.images.size > 0) {
startAnrCrashZipUpload(appBackgroundView)
}
}
}
@@ -717,9 +882,6 @@ object AlfredManager {
eventStartRecordingTime: Long? = null,
index: Int? = null
) {
sessionIdForCrash = alfredSessionId
sessionStartRecordingTimeForCrash = sessionStartRecordingTime
eventStartRecordingTimeForCrash = eventStartRecordingTime
val fileList = ArrayList<String>()
imagePathList.forEach { screenShotPathHelper ->
screenShotPathHelper.screenShotPath?.let { screenShotPath ->
@@ -731,15 +893,25 @@ object AlfredManager {
val zipFilePath = applicationContext.filesDir.path + "/" + zipFileName
if (zip(fileList, zipFilePath) == true) {
clearScreenShot(imagePathList)
getPreSignedUrl(zipFileName, true, index = index)
getPreSignedUrl(
zipFileName,
index = index,
workManagerFlow = true,
dumpFlow = true,
alfredSessionId = alfredSessionId,
eventStartRecordingTime = eventStartRecordingTime,
sessionStartRecordingTime = sessionStartRecordingTime
)
}
}
private fun toZip(
imagePathList: List<ScreenShotPathHelper>
) {
val zipFileName = config.getAlfredSessionId() + UUID.randomUUID().toString()
config.setZipFileName(zipFileName)
val zipFilePath: String =
applicationContext.filesDir.path + "/" + config.getAlfredSessionId() + config.getSessionStartRecordingTime()
applicationContext.filesDir.path + "/" + zipFileName
val fileList = ArrayList<String>()
imagePathList.forEach { screenShotPathHelper ->
screenShotPathHelper.screenShotPath?.let { screenShotPath ->
@@ -749,12 +921,11 @@ object AlfredManager {
}
}
if (zip(fileList, zipFilePath) == true) {
deleteScreenShot()
deleteScreenShot(imagePathList)
config.setNextEventStartRecordingTime()
}
}
fun handleTouchEvent(
currentTouchEvent: MotionEvent?,
screenName: String? = null,
@@ -807,46 +978,22 @@ object AlfredManager {
}
}
fun handleScreenTransitionEvent(
currentScreenName: String?, previousScreenName: String?, screenTransitionDuration: Long
) {
if (config.getAlfredStatus() && config.getMetricsApiEnableStatus()) {
val screenTransitionAttributes: HashMap<String, Any> = hashMapOf()
screenTransitionAttributes.apply {
this[AlfredConstants.CURRENT_SCREEN_NAME] = currentScreenName.orEmpty()
this[AlfredConstants.PREVIOUS_SCREEN_NAME] = previousScreenName.orEmpty()
this[AlfredConstants.LOAD_TIME] = screenTransitionDuration
}
coroutineDispatcher.executor.execute {
val screenTransitionEvent = buildAppPerformanceEvent(
eventName = AlfredConstants.SCREEN_TRANSITION_METRICS,
attribute = screenTransitionAttributes,
eventType = AlfredConstants.SCREEN_TRANSITION_METRICS
)
AlfredDispatcher.addTaskToQueue(
AddMetricTask(
screenTransitionEvent, applicationContext
)
)
}
}
}
fun handleAnrEvent(
anrEventProperties: Map<String, String>, anrView: View, screenName: String? = null
) {
startAnrCrashZipUpload(anrView)
coroutineDispatcher.executor.execute {
val event = buildEvent(
AlfredConstants.ANR_EVENT, anrEventProperties as HashMap<String, String>,
screenName = screenName,
moduleName = currentModuleName
)
AlfredDispatcher.addTaskToQueue(AddEventTask(event, this.applicationContext))
if (config.getAlfredSessionId().isNotEmpty()) {
coroutineDispatcher.executor.execute {
val event = buildEvent(
AlfredConstants.ANR_EVENT, anrEventProperties as HashMap<String, String>,
screenName = screenName,
moduleName = currentModuleName
)
AlfredDispatcher.addTaskToQueue(AddEventTask(event, applicationContext))
}
}
}
fun handleSWWEvent(
screenName: String? = null, swwEventProperties: Map<String, String>
) {
@@ -871,14 +1018,16 @@ object AlfredManager {
screenName: String? = null
) {
startAnrCrashZipUpload(crashView)
coroutineDispatcher.executor.execute {
val event = buildEvent(
AlfredConstants.CRASH_ANALYTICS_EVENT,
crashEventProperties as HashMap<String, String>,
screenName = screenName,
moduleName = currentModuleName
)
AlfredDispatcher.addTaskToQueue(AddEventTask(event, applicationContext))
if (config.getAlfredSessionId().isNotEmpty()) {
coroutineDispatcher.executor.execute {
val event = buildEvent(
AlfredConstants.CRASH_ANALYTICS_EVENT,
crashEventProperties as HashMap<String, String>,
screenName = screenName,
moduleName = currentModuleName
)
AlfredDispatcher.addTaskToQueue(AddEventTask(event, applicationContext))
}
}
}

View File

@@ -19,7 +19,7 @@ import com.navi.alfred.db.model.ZipDetailsHelper
@Database(
entities = [AnalyticsEvent::class, ScreenShotPathHelper::class, ZipDetailsHelper::class, ApiMetricHelper::class],
version = 2,
version = 3,
exportSchema = true
)

View File

@@ -35,7 +35,7 @@ data class ZipDetailsHelper(
@ColumnInfo(name = "alfredSessionId") val alfredSessionId: String,
@ColumnInfo(name = "sessionStartRecordingTime") val sessionStartRecordingTime: Long,
@ColumnInfo(name = "eventStartRecordingTime") val eventStartRecordingTime: Long,
@ColumnInfo(name = "screenShotList") val screenShotList: String?
@ColumnInfo(name = "zipFileName") val zipFileName: String
) {
@PrimaryKey(autoGenerate = true)
var id: Int = 0

View File

@@ -0,0 +1,18 @@
package com.navi.alfred.model
import com.navi.alfred.db.model.ScreenShotPathHelper
import java.util.*
data class ErrorMessage(
var statusCode: Int? = null,
var message: String? = null
)
data class WorkManagerFailureInputData(
var alfredSessionId: String? = "",
var sessionStartRecordingTime: Long = 0L,
var eventStartRecordingTime: Long = 0L,
var screenShots: List<ScreenShotPathHelper> = emptyList(),
val id: UUID
)

View File

@@ -7,6 +7,7 @@
package com.navi.alfred.network
import com.navi.alfred.model.AnalyticsRequest
import com.navi.alfred.model.EventMetricRequest
import com.navi.alfred.model.SessionRequest
import com.navi.alfred.network.model.CruiseResponse
@@ -17,7 +18,7 @@ import retrofit2.Response
class AlfredNetworkRepository {
suspend fun sendEvents(
url: String, analyticsRequest: com.navi.alfred.model.AnalyticsRequest
url: String, analyticsRequest: AnalyticsRequest
): Response<Unit> {
return AlfredRetrofitProvider.getApiService()
.sendEvents(url, "application/json", ALFRED, analyticsRequest)

View File

@@ -12,21 +12,19 @@ import com.chuckerteam.chucker.api.ChuckerCollector
import com.chuckerteam.chucker.api.ChuckerInterceptor
import com.google.gson.GsonBuilder
import com.navi.alfred.AlfredManager
import com.navi.alfred.BuildConfig
import com.navi.alfred.deserializer.AnalyticsDataDeserializer
import com.navi.alfred.deserializer.MetricsDataDeserializer
import com.navi.alfred.deserializer.SessionDataDeserializer
import com.navi.alfred.model.AnalyticsRequest
import com.navi.alfred.model.EventMetricRequest
import com.navi.alfred.model.SessionRequest
import com.navi.alfred.utils.AlfredConstants.API_FAILURE
import com.navi.alfred.utils.AlfredConstants.API_FAILURE_CODE
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import com.navi.alfred.utils.handleException
import com.navi.alfred.utils.orZero
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.IOException
import java.util.concurrent.TimeUnit
object AlfredRetrofitProvider {
@@ -36,26 +34,28 @@ object AlfredRetrofitProvider {
private lateinit var apiService: AlfredRetrofitService
private lateinit var okHttpClient: OkHttpClient
private val headerInterceptor: Interceptor
get() = Interceptor { chain ->
val request = chain.request()
val response: Response = try {
val response = try {
chain.proceed(request).newBuilder().build()
} catch (e: IOException) {
} catch (e: Exception) {
val errorMessage = handleException(e)
// A mocked response in case of n/w exception
Response.Builder()
.request(request)
.code(API_FAILURE_CODE)
.message(API_FAILURE)
.build()
Response.Builder().request(request).protocol(Protocol.HTTP_2)
.code(errorMessage.statusCode.orZero())
.body(ResponseBody.create("application/json".toMediaTypeOrNull(), "{}"))
.message(errorMessage.message.orEmpty()).build()
}
response
}
fun init(context: Context) {
okHttpClient = OkHttpClient.Builder().apply {
connectTimeout(20, TimeUnit.SECONDS).readTimeout(20, TimeUnit.SECONDS)
if (BuildConfig.DEBUG && !AlfredManager.config.getDisableChuckerStatus()) {
connectTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).writeTimeout(30,TimeUnit.SECONDS)
if (BuildConfig.DEBUG && !AlfredManager.config.getDisableAlfredLogsStatus()) {
addInterceptor(loggingInterceptor())
addInterceptor(
ChuckerInterceptor.Builder(context).collector(ChuckerCollector(context))
@@ -63,6 +63,8 @@ object AlfredRetrofitProvider {
)
}
addInterceptor(headerInterceptor)
connectionPool(ConnectionPool(0, 5, TimeUnit.MINUTES))
.protocols(listOf(Protocol.HTTP_1_1))
}.build()
apiService = getRetrofit().create(AlfredRetrofitService::class.java)
}
@@ -76,7 +78,7 @@ object AlfredRetrofitProvider {
BASE_URL_DEBUG
}
val providesDeserializer = GsonBuilder().registerTypeAdapter(
com.navi.alfred.model.AnalyticsRequest::class.java,
AnalyticsRequest::class.java,
AnalyticsDataDeserializer()
).registerTypeAdapter(SessionRequest::class.java, SessionDataDeserializer())
.registerTypeAdapter(EventMetricRequest::class.java, MetricsDataDeserializer()).create()

View File

@@ -7,6 +7,7 @@
package com.navi.alfred.network
import com.navi.alfred.model.AnalyticsRequest
import com.navi.alfred.model.EventMetricRequest
import com.navi.alfred.model.SessionRequest
import com.navi.alfred.network.model.CruiseResponse
@@ -27,7 +28,7 @@ interface AlfredRetrofitService {
@Url url: String,
@Header(CONTENT_TYPE) contentType: String,
@Header(X_TARGET) target: String,
@Body analyticsRequest: com.navi.alfred.model.AnalyticsRequest
@Body analyticsRequest: AnalyticsRequest
): Response<Unit>
@GET("ingest/session/pre-sign/{sessionId}")

View File

@@ -37,6 +37,9 @@ data class OsConfig(
data class MetricsConfig(
@SerializedName("disable_api_performance") val disableApiPerformance: Boolean? = null,
@SerializedName("disable_api_response") val disableApiResponse: Boolean? = null,
@SerializedName("enabled_api_paths") val enabledApiPaths: List<String>? = null,
@SerializedName("disable_api_request") val disableApiRequest: Boolean? = null,
@SerializedName("disable_cpu_monitoring") val disableCpuMonitoring: Boolean? = null,
@SerializedName("disable_memory_monitoring") val disableMemoryMonitoring: Boolean? = null,
@SerializedName("disable_remote_logging") val disableRemoteLogging: Boolean? = null,

View File

@@ -9,6 +9,7 @@ package com.navi.alfred.utils
object AlfredConstants {
const val CODE_API_SUCCESS = 200
const val CODE_API_BAD_REQUEST = 400
const val UNDERSCORE = "_"
const val ADD_EVENT_TASK = "AddEventTask"
const val ADD_API_METRIC_TASK = "AddMetricTask"
@@ -24,8 +25,6 @@ object AlfredConstants {
const val QA = "qa"
const val TOUCH_EVENT = "TOUCH_EVENT"
const val SCROLL_EVENT = "SCROLL_EVENT"
const val SCREEN_WIDTH = "SCREEN_WIDTH"
const val SCREEN_HEIGHT = "SCREEN_HEIGHT"
const val START_X = "START_X"
const val START_Y = "START_Y"
const val END_X = "END_X"
@@ -37,7 +36,6 @@ object AlfredConstants {
const val ALFRED_SESSION_ID = "ALFRED_SESSION_ID"
const val API_METRIC_EVENT_NAME = "API_METRIC_EVENT"
const val API_METRICS = "API_METRICS"
const val SCREEN_TRANSITION_METRICS = "SCREEN_TRANSITION_METRICS"
const val SESSION_START_RECORDING_TIME = "SESSION_START_RECORDING_TIME"
const val EVENT_START_RECORDING_TIME = "EVENT_START_RECORDING_TIME"
const val URL = "url"
@@ -50,6 +48,8 @@ object AlfredConstants {
const val DURATION_IN_MS = "duration_in_ms"
const val BYTES_RECEIVED = "bytes_received"
const val BYTES_SENT = "bytes_sent"
const val RESPONSE_BODY = "response_body"
const val REQUEST_BODY = "request_body"
const val ALFRED = "ALFRED"
const val CONTENT_TYPE = "Content-Type"
const val X_TARGET = "X-Target"
@@ -65,15 +65,15 @@ object AlfredConstants {
const val REASON = "REASON"
const val CODE = "CODE"
const val STATUS_CODE = "STATUS_CODE"
const val EVENT_DB_NAME = "navi-analytics"
const val ZIP_FILE_EXTENSION = ".zip"
const val IMAGE_FILE_EXTENSION = ".jpeg"
const val SYNC_EVENT_TASK = "SyncEventTask"
const val WORKER_ZIP_FILENAME_ENDPOINT = "WORKER_ZIP_FILENAME_ENDPOINT"
const val DISABLE_ALFRED_LOGS = "DISABLE_ALFRED_LOGS"
const val DISABLE_CDN_LOGS = "DISABLE_CDN_LOGS"
const val CURRENT_SCREEN_NAME = "current_screen_name"
const val PREVIOUS_SCREEN_NAME = "previous_screen_name"
const val LOAD_TIME = "load_time_in_ms"
const val DISABLE_CHUCKER = "DISABLE_CHUCKER"
const val API_FAILURE = "API_FAILURE"
const val API_FAILURE_CODE = 300
const val SCREEN_TRANSITION_METRICS = "SCREEN_TRANSITION_METRICS"
const val ZIP_FILE_EXTENSION = ".zip"
const val SYNC_EVENT_TASK = "SyncEventTask"
const val IMAGE_FILE_EXTENSION = ".jpeg"
const val EVENT_DB_NAME = "navi-analytics"
}

View File

@@ -1,10 +0,0 @@
package com.navi.alfred.utils
import com.google.firebase.crashlytics.FirebaseCrashlytics
object AlfredHelper {
fun recordException(e: Throwable) {
FirebaseCrashlytics.getInstance().recordException(e)
}
}

View File

@@ -0,0 +1,13 @@
package com.navi.alfred.utils
object ApiConstants {
const val API_CONNECT_TIMEOUT_VALUE = 20L
const val API_SUCCESS_CODE = 200
const val API_CODE_ERROR = 20
const val NO_INTERNET = 23
const val API_CODE_SOCKET_TIMEOUT = 24
const val API_WRONG_ERROR_RESPONSE = 25
const val API_CODE_UNKNOWN_HOST = 21
const val API_CODE_CONNECT_EXCEPTION = 22
const val API_CODE_SOCKET = 26
}

View File

@@ -0,0 +1,5 @@
package com.navi.alfred.utils
fun Int?.orZero() = this ?: 0
fun Boolean?.orFalse() = this ?: false

View File

@@ -0,0 +1,59 @@
/*
*
* * Copyright © 2022-2023 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.alfred.utils
import com.google.gson.JsonParseException
import com.navi.alfred.AlfredManager
import com.navi.alfred.model.ErrorMessage
import java.net.ConnectException
import java.net.NetworkInterface
import java.net.SocketException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
fun handleException(e: Throwable): ErrorMessage {
val errorMessage = ErrorMessage()
if (!isNetworkAvailable(AlfredManager.applicationContext)) {
errorMessage.statusCode = ApiConstants.NO_INTERNET
} else if (e is ConnectException) {
errorMessage.statusCode = ApiConstants.API_CODE_CONNECT_EXCEPTION
} else if (e is UnknownHostException) {
errorMessage.statusCode = ApiConstants.API_CODE_UNKNOWN_HOST
} else if (e is SocketTimeoutException) {
errorMessage.statusCode = ApiConstants.API_CODE_SOCKET_TIMEOUT
} else if (e is JsonParseException) {
errorMessage.statusCode = ApiConstants.API_WRONG_ERROR_RESPONSE
} else if (e is SocketException) {
errorMessage.statusCode = ApiConstants.API_CODE_SOCKET
}
else {
errorMessage.statusCode = ApiConstants.API_CODE_ERROR
}
errorMessage.message = e.message.toString()
return errorMessage
}
fun getIPAddress(): String? {
try {
val networkInterfaces = NetworkInterface.getNetworkInterfaces()
while (networkInterfaces.hasMoreElements()) {
val networkInterface = networkInterfaces.nextElement()
val inetAddresses = networkInterface.inetAddresses
while (inetAddresses.hasMoreElements()) {
val inetAddress = inetAddresses.nextElement()
if (!inetAddress.isLoopbackAddress && !inetAddress.isLinkLocalAddress && inetAddress.isSiteLocalAddress) {
return inetAddress.hostAddress
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
return null
}

View File

@@ -19,12 +19,13 @@ import android.os.StatFs
import android.telephony.TelephonyManager
import android.view.MotionEvent
import android.view.View
import com.navi.alfred.utils.ScreenShotStorageHelper
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.navi.alfred.AlfredManager
import com.navi.alfred.db.AlfredDatabaseHelper
import com.navi.alfred.db.model.ScreenShotPathHelper
import com.navi.alfred.model.NaviMotionEvent
import com.navi.alfred.utils.AlfredConstants.IMAGE_FILE_EXTENSION
import com.navi.alfred.utils.AlfredConstants.UNDERSCORE
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -34,7 +35,6 @@ import java.io.*
import java.lang.Math.subtractExact
import java.util.*
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream
import kotlin.math.abs
@@ -82,17 +82,21 @@ fun combineScreenshots(
}
var screenWidth = Resources.getSystem().displayMetrics.widthPixels / 2
var screenHeight = Resources.getSystem().displayMetrics.heightPixels / 2
if (!isResolutionEven(screenWidth, screenHeight)) {
screenHeight += 1
if (!isResolutionEven(screenWidth)) {
screenWidth += 1
}
if (!isResolutionEven(screenHeight)) {
screenHeight += 1
}
val combinedBitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(combinedBitmap)
canvas.drawBitmap(backgroundScreenshot, 0f, 0f, null)
var bottomSheetLeft = (screenWidth - bottomSheetScreenshot.width) / 2f
var bottomSheetTop = screenHeight - bottomSheetScreenshot.height.toFloat()
if (!isResolutionEven(bottomSheetLeft.toInt(), bottomSheetTop.toInt())) {
if (!isResolutionEven(bottomSheetLeft.toInt())) {
bottomSheetLeft = (bottomSheetLeft.toInt() + 1).toFloat()
}
if (!isResolutionEven(bottomSheetTop.toInt())) {
bottomSheetTop = (bottomSheetTop.toInt() + 1).toFloat()
}
canvas.drawBitmap(bottomSheetScreenshot, bottomSheetLeft, bottomSheetTop, null)
@@ -169,8 +173,10 @@ fun createBitmapForView(view: View): Pair<Canvas, Bitmap>? {
var width = view.width / 2
var height = view.height / 2
if (width > 0 && height > 0) {
if (!isResolutionEven(width, height)) {
if (!isResolutionEven(width)) {
width += 1
}
if (!isResolutionEven(height)) {
height += 1
}
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
@@ -185,8 +191,12 @@ fun createBitmapForView(view: View): Pair<Canvas, Bitmap>? {
fun zip(_files: ArrayList<String>, zipFilePath: String?): Boolean? {
val buffer = 1000
try {
zipFilePath?.let { zipFile ->
File(zipFile)
zipFilePath?.let { path ->
if (File(path).exists())
return true
else {
File(path)
}
}
var origin: BufferedInputStream? = null
val dest = FileOutputStream(zipFilePath)
@@ -215,14 +225,13 @@ fun zip(_files: ArrayList<String>, zipFilePath: String?): Boolean? {
return null
}
fun clearScreenShot(path: List<ScreenShotPathHelper>): Boolean {
fun clearScreenShot(path: List<ScreenShotPathHelper>) {
path.forEach { data ->
val file = data.screenShotPath?.let { File(it) }
if (file?.exists() == true) {
file.delete()
}
}
return true
}
fun isScreenDisabled(screenName: String? = null, moduleName: String? = null): Boolean {
@@ -293,7 +302,7 @@ fun getNetworkType(context: Context): String {
TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyManager.NETWORK_TYPE_HSDPA, TelephonyManager.NETWORK_TYPE_HSUPA, TelephonyManager.NETWORK_TYPE_HSPA, TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyManager.NETWORK_TYPE_HSPAP -> "3G"
TelephonyManager.NETWORK_TYPE_LTE -> "4G"
TelephonyManager.NETWORK_TYPE_NR -> "5G"
else -> "Unknown" + AlfredConstants.UNDERSCORE + mTelephonyManager.networkType
else -> "Unknown" + UNDERSCORE + mTelephonyManager.networkType
}
} catch (e: Exception) {
e.log()
@@ -305,27 +314,23 @@ fun getCarrierName(context: Context): String? {
return try {
(context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager).networkOperatorName
} catch (e: Exception) {
e.log()
e.log()
null
}
}
fun Int?.orZero() = this ?: 0
fun Float?.orZero() = this ?: 0F
fun getBatteryPercentageForDevice(context: Context): Float {
fun getBatteryPercentage(context: Context): Float {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY).toFloat()
}
fun getMemoryUsageForDevice(): Float {
fun getMemoryUsage(): Float {
val runtime = Runtime.getRuntime()
val usedMemory = runtime.totalMemory() - runtime.freeMemory()
return usedMemory / (1024f * 1024f)
}
fun getCpuUsageForDevice(): Float {
fun getCpuUsage(): Float {
val command = "top -n 1 -d 1"
val process = Runtime.getRuntime().exec(command)
val reader = BufferedReader(InputStreamReader(process.inputStream))
@@ -345,15 +350,7 @@ fun getCpuUsageForDevice(): Float {
}
fun hasFilesInZip(zipFilePath: String): Boolean {
val zipFile = ZipFile(zipFilePath)
val entries = zipFile.entries()
val hasEntries = entries.hasMoreElements()
zipFile.close()
return hasEntries
}
fun getStorageUsageForDevice(context: Context): Pair<Long, Long> {
fun getStorageUsage(context: Context): Pair<Long, Long> {
val path = context.filesDir.path
val stat = StatFs(path)
val blockSize = stat.blockSizeLong
@@ -376,24 +373,23 @@ private fun Any.tag(): String {
}
}
private fun isResolutionEven(width: Int, height: Int): Boolean {
if (width.mod(2) == 0 && height.mod(2) == 0) {
return true
}
return false
}
fun java.lang.Exception.log() {
if (AlfredManager.config.isQa()) {
Timber.tag(tag()).e(this)
}
AlfredHelper.recordException(this)
recordException(this)
}
fun getScreenWidth(): Int {
return Resources.getSystem().displayMetrics.widthPixels
fun isNetworkAvailable(context: Context): Boolean {
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
return connectivityManager?.activeNetworkInfo?.isConnected.orFalse()
}
fun getScreenHeight(): Int {
return Resources.getSystem().displayMetrics.heightPixels
private fun isResolutionEven(size: Int): Boolean {
return size.mod(2) == 0
}
fun recordException(e: Throwable) {
FirebaseCrashlytics.getInstance().recordException(e)
}

View File

@@ -1,15 +1,15 @@
package com.navi.alfred.worker
import android.content.Context
import android.util.Log
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.navi.alfred.AlfredManager
import com.navi.alfred.AlfredManager.workFailureData
import com.navi.alfred.db.model.ScreenShotPathHelper
import com.navi.alfred.model.WorkManagerFailureInputData
import com.navi.alfred.utils.AlfredConstants
import com.navi.alfred.utils.checkFileExists
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.lang.reflect.Type
@@ -29,10 +29,19 @@ class UploadFileWorker(
val listType: Type = object : TypeToken<List<ScreenShotPathHelper?>?>() {}.type
val screenShots: List<ScreenShotPathHelper> =
Gson().fromJson(screenShotList.toString(), listType)
val zipFileName = alfredSessionId + sessionStartRecordingTime.toString()
val zipFileName =
alfredSessionId + sessionStartRecordingTime + AlfredConstants.WORKER_ZIP_FILENAME_ENDPOINT
workFailureData.add(
WorkManagerFailureInputData(
alfredSessionId = alfredSessionId,
sessionStartRecordingTime,
eventStartRecordingTime,
screenShots,
id
)
)
try {
if (alfredSessionId == null || sessionStartRecordingTime == 0L || eventStartRecordingTime == 0L) {
handleWorkFailure(zipFileName)
Result.failure()
} else {
AlfredManager.toZipForWorkManager(screenShots, zipFileName,sessionStartRecordingTime,alfredSessionId, eventStartRecordingTime)
@@ -40,13 +49,8 @@ class UploadFileWorker(
}
} catch (e: Exception) {
e.printStackTrace()
handleWorkFailure(zipFileName)
Result.failure()
Result.retry()
}
}
private fun handleWorkFailure(zipFileName:String) {
checkFileExists(zipFileName, context = applicationContext)?.delete()
}
}