Added latest alfred changes from super app repo (#9)
This commit is contained in:
committed by
Shivam Goyal
parent
029f88c8d4
commit
c2be31c426
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2022-2023 by Navi Technologies Limited
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
@@ -12,7 +12,9 @@ import android.provider.Settings
|
||||
import android.text.TextUtils
|
||||
import com.navi.alfred.utils.AlfredConstants
|
||||
import com.navi.alfred.utils.getCarrierName
|
||||
import com.navi.alfred.utils.getNetworkType
|
||||
import java.util.*
|
||||
|
||||
data class AlfredConfig(
|
||||
private var appVersionCode: String = "",
|
||||
private var appVersionName: String = "",
|
||||
@@ -40,23 +42,22 @@ 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 maskingEnabledScreenList: List<String>? = null,
|
||||
private var disableModuleList: List<String>? = null,
|
||||
private var snapshotPerSecond: Int = 1,
|
||||
private var enableAlfred: Boolean = false,
|
||||
private var disableDialogScreenShot: Boolean = false,
|
||||
private var zipFileName: String? = null,
|
||||
private var disableAlfredLogs: Boolean = true
|
||||
|
||||
) {
|
||||
|
||||
fun getDeviceId(): String = Settings.System.getString(
|
||||
AlfredManager.applicationContext.contentResolver, Settings.Secure.ANDROID_ID
|
||||
)
|
||||
fun getDeviceId(): String =
|
||||
Settings.System.getString(
|
||||
AlfredManager.applicationContext.contentResolver,
|
||||
Settings.Secure.ANDROID_ID
|
||||
)
|
||||
|
||||
fun setEventStartRecordingTime(setToNext: Boolean? = false) {
|
||||
if (setToNext == true) {
|
||||
@@ -133,7 +134,7 @@ data class AlfredConfig(
|
||||
|
||||
fun getNetworkCarrier(): String? = getCarrierName(AlfredManager.applicationContext)
|
||||
|
||||
fun getNetworkType(): String = com.navi.alfred.utils.getNetworkType(AlfredManager.applicationContext)
|
||||
fun getNetworkType(): String = getNetworkType(AlfredManager.applicationContext)
|
||||
|
||||
fun getBatteryPercentage(): Float =
|
||||
com.navi.alfred.utils.getBatteryPercentage(AlfredManager.applicationContext)
|
||||
@@ -173,12 +174,15 @@ data class AlfredConfig(
|
||||
this.batteryPercentageBeforeEventStart = getBatteryPercentage()
|
||||
}
|
||||
|
||||
fun getCpuUsage(): Float = getCpuUsage()
|
||||
fun getCpuUsage(): Float = com.navi.alfred.utils.getCpuUsage()
|
||||
|
||||
fun getMemoryUsage(): Float = getMemoryUsage()
|
||||
fun getMemoryUsage(): Float = com.navi.alfred.utils.getMemoryUsage()
|
||||
|
||||
fun getStorageUsage(): Float {
|
||||
val (totalSize, freeSize) = com.navi.alfred.utils.getStorageUsage(context = AlfredManager.applicationContext)
|
||||
val (totalSize, freeSize) =
|
||||
com.navi.alfred.utils.getStorageUsage(
|
||||
context = AlfredManager.applicationContext
|
||||
)
|
||||
return (totalSize - freeSize).toFloat()
|
||||
}
|
||||
|
||||
@@ -186,6 +190,10 @@ data class AlfredConfig(
|
||||
this.disableScreenList = disableScreenList
|
||||
}
|
||||
|
||||
fun setMaskingEnabledScreenList(maskingEnabledScreenList: List<String>) {
|
||||
this.maskingEnabledScreenList = maskingEnabledScreenList
|
||||
}
|
||||
|
||||
fun setDisableModuleList(disableModuleList: List<String>) {
|
||||
this.disableModuleList = disableModuleList
|
||||
}
|
||||
@@ -212,6 +220,8 @@ data class AlfredConfig(
|
||||
|
||||
fun getDisableScreenList(): List<String>? = this.disableScreenList
|
||||
|
||||
fun getMaskingEnabledScreenList(): List<String>? = this.maskingEnabledScreenList
|
||||
|
||||
fun setCpuEnableStatus(status: Boolean) {
|
||||
this.cpuEnableStatus = status
|
||||
}
|
||||
@@ -227,25 +237,11 @@ data class AlfredConfig(
|
||||
fun setApiMetricsEnableStatus(status: Boolean) {
|
||||
this.metricsApiEnableStatus = status
|
||||
}
|
||||
|
||||
fun getMetricsApiEnableStatus(): Boolean = this.metricsApiEnableStatus
|
||||
|
||||
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 setDisableDialogScreenShot(status: Boolean) {
|
||||
this.disableDialogScreenShot = status
|
||||
}
|
||||
|
||||
fun getDisableDialogScreenShot(): Boolean {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2022-2023 by Navi Technologies Limited
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
@@ -18,14 +18,22 @@ import com.navi.alfred.db.model.ScreenShotPathHelper
|
||||
import com.navi.alfred.db.model.ZipDetailsHelper
|
||||
|
||||
@Database(
|
||||
entities = [AnalyticsEvent::class, ScreenShotPathHelper::class, ZipDetailsHelper::class, ApiMetricHelper::class],
|
||||
entities =
|
||||
[
|
||||
AnalyticsEvent::class,
|
||||
ScreenShotPathHelper::class,
|
||||
ZipDetailsHelper::class,
|
||||
ApiMetricHelper::class
|
||||
],
|
||||
version = 3,
|
||||
exportSchema = true
|
||||
)
|
||||
|
||||
abstract class AlfredDatabase : RoomDatabase() {
|
||||
abstract fun analyticsDao(): AnalyticsDAO
|
||||
|
||||
abstract fun screenShotDao(): ScreenShotDao
|
||||
|
||||
abstract fun zipDetailsDao(): ZipDetailsDao
|
||||
|
||||
abstract fun apiMetricDao(): ApiMetricDao
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ object AlfredDatabaseHelper {
|
||||
INSTANCE
|
||||
}
|
||||
val instance =
|
||||
Room.databaseBuilder(context, AlfredDatabase::class.java, EVENT_DB_NAME).fallbackToDestructiveMigration()
|
||||
Room.databaseBuilder(context, AlfredDatabase::class.java, EVENT_DB_NAME)
|
||||
.fallbackToDestructiveMigration()
|
||||
.build()
|
||||
INSTANCE = instance
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ import com.navi.alfred.db.model.ZipDetailsHelper
|
||||
|
||||
@Dao
|
||||
interface AnalyticsDAO {
|
||||
@Insert
|
||||
fun insertEvent(event: AnalyticsEvent)
|
||||
@Insert fun insertEvent(event: AnalyticsEvent)
|
||||
|
||||
@Query("SELECT * FROM AnalyticsEvent ORDER BY time ASC LIMIT :thresholdValue")
|
||||
fun fetchEvents(thresholdValue: Int): List<AnalyticsEvent>
|
||||
@@ -27,9 +26,7 @@ interface AnalyticsDAO {
|
||||
@Query("DELETE FROM AnalyticsEvent WHERE eventId IN (:idList)")
|
||||
fun deleteEvents(idList: List<Int>)
|
||||
|
||||
@Query("SELECT count(*) FROM AnalyticsEvent")
|
||||
fun getEventCount(): Int
|
||||
|
||||
@Query("SELECT count(*) FROM AnalyticsEvent") fun getEventCount(): Int
|
||||
}
|
||||
|
||||
@Dao
|
||||
@@ -47,37 +44,30 @@ interface ScreenShotDao {
|
||||
@Query("DELETE FROM ScreenShotPathHelper WHERE id IN (:idList)")
|
||||
fun deleteScreenShot(idList: List<Int>)
|
||||
|
||||
@Query("DELETE FROM ScreenShotPathHelper")
|
||||
fun deleteAllScreenShot()
|
||||
@Query("DELETE FROM ScreenShotPathHelper") fun deleteAllScreenShot()
|
||||
|
||||
@Query("SELECT count(*) FROM ScreenShotPathHelper")
|
||||
fun getScreenShotCount(): Int
|
||||
@Query("SELECT count(*) FROM ScreenShotPathHelper") fun getScreenShotCount(): Int
|
||||
}
|
||||
|
||||
@Dao
|
||||
interface ZipDetailsDao{
|
||||
interface ZipDetailsDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insert(data: ZipDetailsHelper)
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(data: ZipDetailsHelper)
|
||||
|
||||
@Query("SELECT count(*) FROM ZipDetailsHelper")
|
||||
fun getZipFilesDetailsCount(): Int
|
||||
@Query("SELECT count(*) FROM ZipDetailsHelper") fun getZipFilesDetailsCount(): Int
|
||||
|
||||
@Query("SELECT * FROM ZipDetailsHelper ORDER BY sessionStartRecordingTime")
|
||||
fun fetchAllZipFilesDetails(): List<ZipDetailsHelper>
|
||||
|
||||
@Query("DELETE FROM ZipDetailsHelper WHERE id = :id")
|
||||
fun deleteZipFileDetail(id: Int)
|
||||
@Query("DELETE FROM ZipDetailsHelper WHERE id = :id") fun deleteZipFileDetail(id: Int)
|
||||
}
|
||||
|
||||
@Dao
|
||||
interface ApiMetricDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insert(data: ApiMetricHelper)
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(data: ApiMetricHelper)
|
||||
|
||||
@Query("SELECT count(*) FROM ApiMetricHelper")
|
||||
fun getApiMetricCount(): Int
|
||||
@Query("SELECT count(*) FROM ApiMetricHelper") fun getApiMetricCount(): Int
|
||||
|
||||
@Query("SELECT * FROM ApiMetricHelper ORDER BY time ASC LIMIT :thresholdValue")
|
||||
fun fetchApiMetric(thresholdValue: Int): List<ApiMetricHelper>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2022-2023 by Navi Technologies Limited
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
@@ -16,8 +16,7 @@ data class AnalyticsEvent(
|
||||
@ColumnInfo(name = "time") val time: Long?,
|
||||
@ColumnInfo(name = "details") val details: String?
|
||||
) {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var eventId: Int = 0
|
||||
@PrimaryKey(autoGenerate = true) var eventId: Int = 0
|
||||
}
|
||||
|
||||
@Entity
|
||||
@@ -25,8 +24,7 @@ data class ScreenShotPathHelper(
|
||||
@ColumnInfo(name = "time") val time: Long?,
|
||||
@ColumnInfo(name = "screenShotPath") val screenShotPath: String?
|
||||
) {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Int = 0
|
||||
@PrimaryKey(autoGenerate = true) var id: Int = 0
|
||||
}
|
||||
|
||||
@Entity
|
||||
@@ -37,8 +35,7 @@ data class ZipDetailsHelper(
|
||||
@ColumnInfo(name = "eventStartRecordingTime") val eventStartRecordingTime: Long,
|
||||
@ColumnInfo(name = "zipFileName") val zipFileName: String
|
||||
) {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Int = 0
|
||||
@PrimaryKey(autoGenerate = true) var id: Int = 0
|
||||
}
|
||||
|
||||
@Entity
|
||||
@@ -46,8 +43,7 @@ data class ApiMetricHelper(
|
||||
@ColumnInfo(name = "time") val time: Long?,
|
||||
@ColumnInfo(name = "metric") val metric: String?
|
||||
) {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Int = 0
|
||||
@PrimaryKey(autoGenerate = true) var id: Int = 0
|
||||
}
|
||||
|
||||
class Converter {
|
||||
@@ -61,8 +57,4 @@ class Converter {
|
||||
fun toDeviceAttributes(data: String): DeviceAttributes {
|
||||
return Gson().fromJson(data, DeviceAttributes::class.java)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.alfred.deserializer
|
||||
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
@@ -8,11 +15,13 @@ import java.lang.reflect.Type
|
||||
|
||||
class AnalyticsDataDeserializer : JsonDeserializer<AnalyticsRequest> {
|
||||
override fun deserialize(
|
||||
json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?
|
||||
json: JsonElement?,
|
||||
typeOfT: Type?,
|
||||
context: JsonDeserializationContext?
|
||||
): AnalyticsRequest? {
|
||||
json?.let {
|
||||
return context?.deserialize(json, AnalyticsRequest::class.java)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.alfred.deserializer
|
||||
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
@@ -8,11 +15,13 @@ import java.lang.reflect.Type
|
||||
|
||||
class MetricsDataDeserializer : JsonDeserializer<EventMetricRequest> {
|
||||
override fun deserialize(
|
||||
json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?
|
||||
json: JsonElement?,
|
||||
typeOfT: Type?,
|
||||
context: JsonDeserializationContext?
|
||||
): EventMetricRequest? {
|
||||
json?.let {
|
||||
return context?.deserialize(json, EventMetricRequest::class.java)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.alfred.deserializer
|
||||
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
@@ -9,11 +16,13 @@ import java.lang.reflect.Type
|
||||
|
||||
class SessionDataDeserializer : JsonDeserializer<SessionRequest> {
|
||||
override fun deserialize(
|
||||
json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?
|
||||
json: JsonElement?,
|
||||
typeOfT: Type?,
|
||||
context: JsonDeserializationContext?
|
||||
): SessionRequest? {
|
||||
json?.let {
|
||||
return context?.deserialize(json, EventMetricRequest::class.java)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2019-2023 by Navi Technologies Limited
|
||||
* * Copyright © 2021-2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
@@ -10,18 +10,15 @@ package com.navi.alfred.dispatcher
|
||||
import com.navi.alfred.worker.AnalyticsTask
|
||||
import com.navi.alfred.worker.AnalyticsTaskProcessor
|
||||
|
||||
/**
|
||||
* handles task of putting events into DB and syncing data with backend
|
||||
*/
|
||||
/** handles task of putting events into DB and syncing data with backend */
|
||||
object AlfredDispatcher {
|
||||
private val taskProcessor: AnalyticsTaskProcessor = AnalyticsTaskProcessor()
|
||||
|
||||
fun addTaskToQueue(task: AnalyticsTask) {
|
||||
taskProcessor.addTask(task)
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes task in a different thread than the Queue
|
||||
*/
|
||||
/** Executes task in a different thread than the Queue */
|
||||
fun executeInNewThread(task: AnalyticsTask) {
|
||||
taskProcessor.executeInNewThread(task)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
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 ErrorMessage(var statusCode: Int? = null, var message: String? = null)
|
||||
|
||||
data class WorkManagerFailureInputData(
|
||||
var alfredSessionId: String? = "",
|
||||
@@ -15,4 +18,4 @@ data class WorkManagerFailureInputData(
|
||||
var eventStartRecordingTime: Long = 0L,
|
||||
var screenShots: List<ScreenShotPathHelper> = emptyList(),
|
||||
val id: UUID
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.alfred.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
@@ -16,5 +23,3 @@ data class MetricAttribute(
|
||||
@SerializedName("module_name") val moduleName: String? = null,
|
||||
@SerializedName("attributes") val attributes: HashMap<String, Any>? = null
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.alfred.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
@@ -21,32 +28,43 @@ data class EventAttribute(
|
||||
|
||||
data class SessionRequest(
|
||||
@SerializedName("base_attributes") val base_attribute: BaseAttribute,
|
||||
@SerializedName("session_upload_event_attributes") val session_upload_event_attributes: SessionEventAttribute
|
||||
@SerializedName("session_upload_event_attributes")
|
||||
val session_upload_event_attributes: SessionEventAttribute
|
||||
)
|
||||
|
||||
data class BaseAttribute(
|
||||
@SerializedName("app_version_code") val appVersionCode: String = AlfredManager.config.getAppVersionCode(),
|
||||
@SerializedName("app_version_name") val appVersionName: String? = AlfredManager.config.getAppVersionName(),
|
||||
@SerializedName("client_ts") val clientTs: Long? = AlfredManager.config.getEventStartRecordingTime(),
|
||||
@SerializedName("app_version_code")
|
||||
val appVersionCode: String = AlfredManager.config.getAppVersionCode(),
|
||||
@SerializedName("app_version_name")
|
||||
val appVersionName: String? = AlfredManager.config.getAppVersionName(),
|
||||
@SerializedName("client_ts")
|
||||
val clientTs: Long? = AlfredManager.config.getEventStartRecordingTime(),
|
||||
@SerializedName("device_id") val deviceId: String? = AlfredManager.config.getDeviceId(),
|
||||
@SerializedName("device_model") val deviceModel: String? = AlfredManager.config.getDeviceModel(),
|
||||
@SerializedName("device_manufacturer") val deviceManufacturer: String? = AlfredManager.config.getManufacturer(),
|
||||
@SerializedName("device_model")
|
||||
val deviceModel: String? = AlfredManager.config.getDeviceModel(),
|
||||
@SerializedName("device_manufacturer")
|
||||
val deviceManufacturer: String? = AlfredManager.config.getManufacturer(),
|
||||
@SerializedName("app_os") val appOs: String? = AlfredManager.config.getOs(),
|
||||
@SerializedName("os_version") val osVersion: String? = AlfredManager.config.getOsVersion(),
|
||||
@SerializedName("latitude") val latitude: Double? = AlfredManager.config.getLatitude(),
|
||||
@SerializedName("longitude") val longitude: Double? = AlfredManager.config.getLongitude(),
|
||||
@SerializedName("customer_id") val customerId: String? = AlfredManager.config.getUserId(),
|
||||
@SerializedName("up_time") val upTime: Long? = null,
|
||||
@SerializedName("carrier_name") val carrierName: String? = AlfredManager.config.getNetworkCarrier(),
|
||||
@SerializedName("carrier_name")
|
||||
val carrierName: String? = AlfredManager.config.getNetworkCarrier(),
|
||||
@SerializedName("parent_session_id") val parentSessionId: String? = null,
|
||||
@SerializedName("event_timestamp") val eventTimeStamp: Long? = AlfredManager.config.getEventTimeStamp(),
|
||||
@SerializedName("session_id") val sessionId: String? = AlfredManager.config.getAlfredSessionId(),
|
||||
@SerializedName("session_time_stamp") val sessionTimeStamp: Long? = AlfredManager.config.getSessionStartRecordingTime(),
|
||||
@SerializedName("event_timestamp")
|
||||
val eventTimeStamp: Long? = AlfredManager.config.getEventTimeStamp(),
|
||||
@SerializedName("session_id")
|
||||
val sessionId: String? = AlfredManager.config.getAlfredSessionId(),
|
||||
@SerializedName("session_time_stamp")
|
||||
val sessionTimeStamp: Long? = AlfredManager.config.getSessionStartRecordingTime(),
|
||||
)
|
||||
|
||||
data class SessionEventAttribute(
|
||||
@SerializedName("event_id") val eventId: String? = AlfredManager.config.getAlfredEventId(),
|
||||
@SerializedName("beginning_device_attributes") val beginningDeviceAttributes: DeviceAttributes? = null,
|
||||
@SerializedName("beginning_device_attributes")
|
||||
val beginningDeviceAttributes: DeviceAttributes? = null,
|
||||
@SerializedName("end_device_attributes") val endDeviceAttributes: DeviceAttributes? = null
|
||||
)
|
||||
|
||||
@@ -55,4 +73,4 @@ data class DeviceAttributes(
|
||||
@SerializedName("cpu") val cpu: Float? = null,
|
||||
@SerializedName("storage") val storage: Float? = null,
|
||||
@SerializedName("memory") val memory: Float? = null,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -18,7 +18,8 @@ import retrofit2.Response
|
||||
|
||||
class AlfredNetworkRepository {
|
||||
suspend fun sendEvents(
|
||||
url: String, analyticsRequest: AnalyticsRequest
|
||||
url: String,
|
||||
analyticsRequest: AnalyticsRequest
|
||||
): Response<Unit> {
|
||||
return AlfredRetrofitProvider.getApiService()
|
||||
.sendEvents(url, "application/json", ALFRED, analyticsRequest)
|
||||
@@ -28,37 +29,34 @@ class AlfredNetworkRepository {
|
||||
return AlfredRetrofitProvider.getApiService().getPreSignedUrl(sessionId, ALFRED)
|
||||
}
|
||||
|
||||
suspend fun sendSession(
|
||||
url: String,
|
||||
sessionRequest: SessionRequest
|
||||
): Response<Unit> {
|
||||
suspend fun sendSession(url: String, sessionRequest: SessionRequest): Response<Unit> {
|
||||
return AlfredRetrofitProvider.getApiService()
|
||||
.sendSession(url, "application/json", ALFRED, sessionRequest)
|
||||
}
|
||||
|
||||
suspend fun uploadZipToS3(
|
||||
preSignedUrl: String, request: RequestBody
|
||||
): Response<Unit> {
|
||||
suspend fun uploadZipToS3(preSignedUrl: String, request: RequestBody): Response<Unit> {
|
||||
return AlfredRetrofitProvider.getApiService().uploadToS3(preSignedUrl, request, ALFRED)
|
||||
}
|
||||
|
||||
suspend fun eventMetric(
|
||||
url: String, metricRequestBody: EventMetricRequest
|
||||
): Response<Unit> {
|
||||
suspend fun eventMetric(url: String, metricRequestBody: EventMetricRequest): Response<Unit> {
|
||||
return AlfredRetrofitProvider.getApiService()
|
||||
.sendMetric(url, ALFRED, "application/json", metricRequestBody)
|
||||
}
|
||||
|
||||
suspend fun cruiseConfig(
|
||||
url: String, appVersionName: String, osVersionCode: String, deviceId: String
|
||||
url: String,
|
||||
appVersionName: String,
|
||||
osVersionCode: String,
|
||||
deviceId: String
|
||||
): Response<CruiseResponse> {
|
||||
return AlfredRetrofitProvider.getApiService().getCruiseConfig(
|
||||
return AlfredRetrofitProvider.getApiService()
|
||||
.getCruiseConfig(
|
||||
url,
|
||||
ALFRED,
|
||||
ALFRED,
|
||||
contentType = "application/json",
|
||||
appVersionName = appVersionName,
|
||||
osVersion = osVersionCode,
|
||||
deviceId = deviceId
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ 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.handleException
|
||||
@@ -34,64 +34,79 @@ 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 = try {
|
||||
chain.proceed(request).newBuilder().build()
|
||||
} catch (e: Exception) {
|
||||
val errorMessage = handleException(e)
|
||||
// A mocked response in case of n/w exception
|
||||
Response.Builder().request(request).protocol(Protocol.HTTP_2)
|
||||
.code(errorMessage.statusCode.orZero())
|
||||
.body(ResponseBody.create("application/json".toMediaTypeOrNull(), "{}"))
|
||||
.message(errorMessage.message.orEmpty()).build()
|
||||
}
|
||||
val response =
|
||||
try {
|
||||
chain.proceed(request).newBuilder().build()
|
||||
} catch (e: Exception) {
|
||||
val errorMessage = handleException(e)
|
||||
// A mocked response in case of n/w exception
|
||||
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(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))
|
||||
.alwaysReadResponseBody(false).build()
|
||||
)
|
||||
}
|
||||
addInterceptor(headerInterceptor)
|
||||
connectionPool(ConnectionPool(0, 5, TimeUnit.MINUTES))
|
||||
.protocols(listOf(Protocol.HTTP_1_1))
|
||||
}.build()
|
||||
okHttpClient =
|
||||
OkHttpClient.Builder()
|
||||
.apply {
|
||||
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))
|
||||
.alwaysReadResponseBody(false)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
addInterceptor(headerInterceptor)
|
||||
connectionPool(ConnectionPool(0, 5, TimeUnit.MINUTES))
|
||||
.protocols(listOf(Protocol.HTTP_1_1))
|
||||
}
|
||||
.build()
|
||||
apiService = getRetrofit().create(AlfredRetrofitService::class.java)
|
||||
}
|
||||
|
||||
private fun getRetrofit(): Retrofit {
|
||||
val baseUrl = if (AlfredManager.config.isQa()) {
|
||||
BASE_URL_QA
|
||||
} else if (AlfredManager.config.isProd()) {
|
||||
BASE_URL_PROD
|
||||
} else {
|
||||
BASE_URL_DEBUG
|
||||
}
|
||||
val providesDeserializer = GsonBuilder().registerTypeAdapter(
|
||||
AnalyticsRequest::class.java,
|
||||
AnalyticsDataDeserializer()
|
||||
).registerTypeAdapter(SessionRequest::class.java, SessionDataDeserializer())
|
||||
.registerTypeAdapter(EventMetricRequest::class.java, MetricsDataDeserializer()).create()
|
||||
return Retrofit.Builder().baseUrl(baseUrl)
|
||||
val baseUrl =
|
||||
if (AlfredManager.config.isQa()) {
|
||||
BASE_URL_QA
|
||||
} else if (AlfredManager.config.isProd()) {
|
||||
BASE_URL_PROD
|
||||
} else {
|
||||
BASE_URL_DEBUG
|
||||
}
|
||||
val providesDeserializer =
|
||||
GsonBuilder()
|
||||
.registerTypeAdapter(
|
||||
com.navi.alfred.model.AnalyticsRequest::class.java,
|
||||
AnalyticsDataDeserializer()
|
||||
)
|
||||
.registerTypeAdapter(SessionRequest::class.java, SessionDataDeserializer())
|
||||
.registerTypeAdapter(EventMetricRequest::class.java, MetricsDataDeserializer())
|
||||
.create()
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(baseUrl)
|
||||
.addConverterFactory(GsonConverterFactory.create(providesDeserializer))
|
||||
.client(okHttpClient).build()
|
||||
.client(okHttpClient)
|
||||
.build()
|
||||
}
|
||||
|
||||
fun getApiService(): AlfredRetrofitService {
|
||||
return apiService
|
||||
}
|
||||
|
||||
private fun loggingInterceptor() = HttpLoggingInterceptor().apply {
|
||||
setLevel(HttpLoggingInterceptor.Level.BODY)
|
||||
}
|
||||
private fun loggingInterceptor() =
|
||||
HttpLoggingInterceptor().apply { setLevel(HttpLoggingInterceptor.Level.BODY) }
|
||||
}
|
||||
|
||||
@@ -69,4 +69,4 @@ interface AlfredRetrofitService {
|
||||
@Header(DEVICE_ID) deviceId: String,
|
||||
@Header(CONTENT_TYPE) contentType: String,
|
||||
): Response<CruiseResponse>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.alfred.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class CruiseResponse(
|
||||
@SerializedName("data") val data: List<CruiseConfig>, @SerializedName("status") val status: Int
|
||||
@SerializedName("data") val data: List<CruiseConfig>,
|
||||
@SerializedName("status") val status: Int
|
||||
)
|
||||
|
||||
data class CruiseConfig(
|
||||
@SerializedName("_id") val id: String, @SerializedName("_source") val source: Source
|
||||
@SerializedName("_id") val id: String,
|
||||
@SerializedName("_source") val source: Source
|
||||
)
|
||||
|
||||
data class Source(
|
||||
@@ -26,7 +35,8 @@ data class RecordingsConfig(
|
||||
@SerializedName("video_quality") val videoQuality: String? = null,
|
||||
@SerializedName("video_recording_policy") val videoRecordingPolicy: String? = null,
|
||||
@SerializedName("disable_screens") val disableScreens: List<String>? = null,
|
||||
@SerializedName("disable_modules") val disableModules: List<String>? = null
|
||||
@SerializedName("disable_modules") val disableModules: List<String>? = null,
|
||||
@SerializedName("masked_enabled_screens") val maskingEnabledScreens: List<String>? = null
|
||||
)
|
||||
|
||||
data class OsConfig(
|
||||
@@ -37,11 +47,8 @@ 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,
|
||||
@SerializedName("enable") val enable: Boolean? = null
|
||||
)
|
||||
)
|
||||
|
||||
@@ -48,8 +48,6 @@ 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"
|
||||
@@ -68,12 +66,9 @@ object AlfredConstants {
|
||||
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 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 SENSITIVE_VIEW_TAG = "sensitive_view"
|
||||
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"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.alfred.utils
|
||||
|
||||
object ApiConstants {
|
||||
@@ -10,4 +17,4 @@ object ApiConstants {
|
||||
const val API_CODE_UNKNOWN_HOST = 21
|
||||
const val API_CODE_CONNECT_EXCEPTION = 22
|
||||
const val API_CODE_SOCKET = 26
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2021-2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.alfred.utils
|
||||
|
||||
fun Int?.orZero() = this ?: 0
|
||||
|
||||
fun Boolean?.orFalse() = this ?: false
|
||||
fun Boolean?.orFalse() = this ?: false
|
||||
|
||||
fun Int?.orZero() = this ?: 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2022-2023 by Navi Technologies Limited
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
@@ -11,12 +11,10 @@ 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)) {
|
||||
@@ -31,29 +29,9 @@ fun handleException(e: Throwable): ErrorMessage {
|
||||
errorMessage.statusCode = ApiConstants.API_WRONG_ERROR_RESPONSE
|
||||
} else if (e is SocketException) {
|
||||
errorMessage.statusCode = ApiConstants.API_CODE_SOCKET
|
||||
}
|
||||
else {
|
||||
} 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
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2022-2023 by Navi Technologies Limited
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2022-2023 by Navi Technologies Limited
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
@@ -19,25 +19,26 @@ import android.os.StatFs
|
||||
import android.telephony.TelephonyManager
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
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.SENSITIVE_VIEW_TAG
|
||||
import com.navi.alfred.utils.AlfredConstants.UNDERSCORE
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.io.*
|
||||
import java.lang.Math.subtractExact
|
||||
import java.util.*
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
import kotlin.math.abs
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
|
||||
suspend fun captureScreen(
|
||||
v: View,
|
||||
@@ -53,11 +54,39 @@ suspend fun captureScreen(
|
||||
return null
|
||||
}
|
||||
if (canvas != null && bmp != null) {
|
||||
withContext(Dispatchers.Main) {
|
||||
try {
|
||||
v.draw(canvas)
|
||||
} catch (e: Exception) {
|
||||
e.log()
|
||||
if (isMaskingEnabled(screenName) || (v.tag == SENSITIVE_VIEW_TAG)) {
|
||||
val maskedViewsList = findViewWithTagRecursive(v, SENSITIVE_VIEW_TAG, mutableListOf())
|
||||
withContext(Dispatchers.Main) {
|
||||
try {
|
||||
if (maskedViewsList.isEmpty()) {
|
||||
v.draw(canvas)
|
||||
} else {
|
||||
val alphaList = mutableListOf<Pair<View, Float>>()
|
||||
|
||||
for (maskedView in maskedViewsList) {
|
||||
alphaList.add(Pair(maskedView, maskedView.alpha))
|
||||
maskedView.alpha = 0.0f
|
||||
}
|
||||
|
||||
v.draw(canvas)
|
||||
|
||||
for (alphaView in alphaList) {
|
||||
val view = alphaView.first
|
||||
view.alpha = alphaView.second
|
||||
}
|
||||
alphaList.clear()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.log()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
withContext(Dispatchers.Main) {
|
||||
try {
|
||||
v.draw(canvas)
|
||||
} catch (e: Exception) {
|
||||
e.log()
|
||||
}
|
||||
}
|
||||
}
|
||||
insertScreenShotPathInDb(scope, context, bmp, bottomSheetFlow)
|
||||
@@ -65,6 +94,19 @@ suspend fun captureScreen(
|
||||
return bmp
|
||||
}
|
||||
|
||||
fun findViewWithTagRecursive(view: View, tag: String, maskedViews: MutableList<View>): List<View> {
|
||||
if (view.tag == tag) {
|
||||
maskedViews.add(view)
|
||||
}
|
||||
|
||||
if (view is ViewGroup) {
|
||||
for (i in 0 until view.childCount) {
|
||||
val childView = view.getChildAt(i)
|
||||
findViewWithTagRecursive(childView, tag, maskedViews)
|
||||
}
|
||||
}
|
||||
return maskedViews
|
||||
}
|
||||
|
||||
fun combineScreenshots(
|
||||
backgroundScreenshot: Bitmap?,
|
||||
@@ -74,29 +116,26 @@ fun combineScreenshots(
|
||||
moduleName: String? = null,
|
||||
scope: CoroutineScope
|
||||
): Bitmap? {
|
||||
if (backgroundScreenshot == null || bottomSheetScreenshot == null || isScreenDisabled(
|
||||
screenName, moduleName
|
||||
)
|
||||
if (
|
||||
backgroundScreenshot == null ||
|
||||
bottomSheetScreenshot == null ||
|
||||
isScreenDisabled(screenName, moduleName)
|
||||
) {
|
||||
return null
|
||||
}
|
||||
var screenWidth = Resources.getSystem().displayMetrics.widthPixels / 2
|
||||
var screenHeight = Resources.getSystem().displayMetrics.heightPixels / 2
|
||||
if (!isResolutionEven(screenWidth)) {
|
||||
screenWidth += 1
|
||||
}
|
||||
if (!isResolutionEven(screenHeight)) {
|
||||
if (!isResolutionEven(screenWidth, screenHeight)) {
|
||||
screenHeight += 1
|
||||
screenWidth += 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())) {
|
||||
if (!isResolutionEven(bottomSheetLeft.toInt(), bottomSheetTop.toInt())) {
|
||||
bottomSheetLeft = (bottomSheetLeft.toInt() + 1).toFloat()
|
||||
}
|
||||
if (!isResolutionEven(bottomSheetTop.toInt())) {
|
||||
bottomSheetTop = (bottomSheetTop.toInt() + 1).toFloat()
|
||||
}
|
||||
canvas.drawBitmap(bottomSheetScreenshot, bottomSheetLeft, bottomSheetTop, null)
|
||||
@@ -105,7 +144,10 @@ fun combineScreenshots(
|
||||
}
|
||||
|
||||
fun insertScreenShotPathInDb(
|
||||
scope: CoroutineScope, context: Context, bitmap: Bitmap?, bottomSheetFlow: Boolean? = false
|
||||
scope: CoroutineScope,
|
||||
context: Context,
|
||||
bitmap: Bitmap?,
|
||||
bottomSheetFlow: Boolean? = false
|
||||
) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
@@ -113,23 +155,22 @@ fun insertScreenShotPathInDb(
|
||||
val fileName = System.currentTimeMillis().toString() + IMAGE_FILE_EXTENSION
|
||||
val path = fileDir.path.plus("/").plus(fileName)
|
||||
val imageUrl = File(path)
|
||||
val fos = FileOutputStream(
|
||||
imageUrl
|
||||
)
|
||||
val videoQuality: Int = when (AlfredManager.config.getVideoQuality()) {
|
||||
VideoQuality.HIGH.name -> {
|
||||
10
|
||||
val fos = FileOutputStream(imageUrl)
|
||||
val videoQuality: Int =
|
||||
when (AlfredManager.config.getVideoQuality()) {
|
||||
VideoQuality.HIGH.name -> {
|
||||
10
|
||||
}
|
||||
VideoQuality.LOW.name -> {
|
||||
6
|
||||
}
|
||||
VideoQuality.MEDIUM.name -> {
|
||||
8
|
||||
}
|
||||
else -> {
|
||||
10
|
||||
}
|
||||
}
|
||||
VideoQuality.LOW.name -> {
|
||||
6
|
||||
}
|
||||
VideoQuality.MEDIUM.name -> {
|
||||
8
|
||||
}
|
||||
else -> {
|
||||
10
|
||||
}
|
||||
}
|
||||
bitmap?.compress(CompressFormat.JPEG, videoQuality, fos)
|
||||
fos.flush()
|
||||
fos.close()
|
||||
@@ -138,9 +179,7 @@ fun insertScreenShotPathInDb(
|
||||
val screenShotDao = db.screenShotDao()
|
||||
try {
|
||||
screenShotDao.insertScreenShotPath(
|
||||
ScreenShotPathHelper(
|
||||
System.currentTimeMillis(), path
|
||||
)
|
||||
ScreenShotPathHelper(System.currentTimeMillis(), path)
|
||||
)
|
||||
ScreenShotStorageHelper.addImage(path)
|
||||
} catch (e: Exception) {
|
||||
@@ -149,16 +188,13 @@ fun insertScreenShotPathInDb(
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.log()
|
||||
|
||||
} catch (e: IOException) {
|
||||
e.log()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun captureScreenshotOfCustomView(
|
||||
view: View
|
||||
): Bitmap? {
|
||||
fun captureScreenshotOfCustomView(view: View): Bitmap? {
|
||||
view.draw(Canvas())
|
||||
val bitmapForCanvas = createBitmapForView(view)
|
||||
try {
|
||||
@@ -173,10 +209,8 @@ 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)) {
|
||||
if (!isResolutionEven(width, height)) {
|
||||
width += 1
|
||||
}
|
||||
if (!isResolutionEven(height)) {
|
||||
height += 1
|
||||
}
|
||||
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
||||
@@ -187,13 +221,11 @@ fun createBitmapForView(view: View): Pair<Canvas, Bitmap>? {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
fun zip(_files: ArrayList<String>, zipFilePath: String?): Boolean? {
|
||||
val buffer = 1000
|
||||
try {
|
||||
zipFilePath?.let { path ->
|
||||
if (File(path).exists())
|
||||
return true
|
||||
if (File(path).exists()) return true
|
||||
else {
|
||||
File(path)
|
||||
}
|
||||
@@ -235,13 +267,15 @@ fun clearScreenShot(path: List<ScreenShotPathHelper>) {
|
||||
}
|
||||
|
||||
fun isScreenDisabled(screenName: String? = null, moduleName: String? = null): Boolean {
|
||||
if (moduleName != null && AlfredManager.config.getDisableModuleList()
|
||||
?.contains(moduleName) == true
|
||||
if (
|
||||
moduleName != null &&
|
||||
AlfredManager.config.getDisableModuleList()?.contains(moduleName) == true
|
||||
) {
|
||||
return true
|
||||
} else {
|
||||
if (screenName != null && AlfredManager.config.getDisableScreenList()
|
||||
?.contains(screenName) == true
|
||||
if (
|
||||
screenName != null &&
|
||||
AlfredManager.config.getDisableScreenList()?.contains(screenName) == true
|
||||
) {
|
||||
return true
|
||||
}
|
||||
@@ -249,6 +283,13 @@ fun isScreenDisabled(screenName: String? = null, moduleName: String? = null): Bo
|
||||
return false
|
||||
}
|
||||
|
||||
fun isMaskingEnabled(screenName: String? = null): Boolean {
|
||||
if (AlfredManager.config.getMaskingEnabledScreenList()?.contains(screenName) == true) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun checkFileExists(fileName: String, context: Context): File? {
|
||||
val file = File(context.filesDir, fileName)
|
||||
return if (file.exists()) {
|
||||
@@ -259,24 +300,26 @@ fun checkFileExists(fileName: String, context: Context): File? {
|
||||
}
|
||||
|
||||
fun getTouchEvent(
|
||||
currentTouchEvent: MotionEvent?, previousTouchEvent: NaviMotionEvent?
|
||||
currentTouchEvent: MotionEvent?,
|
||||
previousTouchEvent: NaviMotionEvent?
|
||||
): Pair<String, HashMap<String, String>> {
|
||||
val properties = HashMap<String, String>()
|
||||
val pointerIndex = currentTouchEvent?.actionIndex ?: 0
|
||||
val eventName = if (difference(currentTouchEvent?.getX(pointerIndex), previousTouchEvent?.positionX) && difference(
|
||||
currentTouchEvent?.getY(pointerIndex), previousTouchEvent?.positionY
|
||||
)
|
||||
) {
|
||||
properties[AlfredConstants.START_X] = previousTouchEvent?.positionX.toString()
|
||||
properties[AlfredConstants.START_Y] = previousTouchEvent?.positionY.toString()
|
||||
AlfredConstants.TOUCH_EVENT
|
||||
} else {
|
||||
properties[AlfredConstants.START_X] = previousTouchEvent?.positionX.toString()
|
||||
properties[AlfredConstants.START_Y] = previousTouchEvent?.positionY.toString()
|
||||
properties[AlfredConstants.END_X] = currentTouchEvent?.rawX.toString()
|
||||
properties[AlfredConstants.END_Y] = currentTouchEvent?.rawY.toString()
|
||||
AlfredConstants.SCROLL_EVENT
|
||||
}
|
||||
val eventName =
|
||||
if (
|
||||
difference(currentTouchEvent?.getX(pointerIndex), previousTouchEvent?.positionX) &&
|
||||
difference(currentTouchEvent?.getY(pointerIndex), previousTouchEvent?.positionY)
|
||||
) {
|
||||
properties[AlfredConstants.START_X] = previousTouchEvent?.positionX.toString()
|
||||
properties[AlfredConstants.START_Y] = previousTouchEvent?.positionY.toString()
|
||||
AlfredConstants.TOUCH_EVENT
|
||||
} else {
|
||||
properties[AlfredConstants.START_X] = previousTouchEvent?.positionX.toString()
|
||||
properties[AlfredConstants.START_Y] = previousTouchEvent?.positionY.toString()
|
||||
properties[AlfredConstants.END_X] = currentTouchEvent?.rawX.toString()
|
||||
properties[AlfredConstants.END_Y] = currentTouchEvent?.rawY.toString()
|
||||
AlfredConstants.SCROLL_EVENT
|
||||
}
|
||||
return Pair(eventName, properties)
|
||||
}
|
||||
|
||||
@@ -298,8 +341,20 @@ fun getNetworkType(context: Context): String {
|
||||
val mTelephonyManager =
|
||||
context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
||||
return when (mTelephonyManager.networkType) {
|
||||
TelephonyManager.NETWORK_TYPE_GPRS, TelephonyManager.NETWORK_TYPE_EDGE, TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyManager.NETWORK_TYPE_IDEN -> "2G"
|
||||
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_GPRS,
|
||||
TelephonyManager.NETWORK_TYPE_EDGE,
|
||||
TelephonyManager.NETWORK_TYPE_CDMA,
|
||||
TelephonyManager.NETWORK_TYPE_1xRTT,
|
||||
TelephonyManager.NETWORK_TYPE_IDEN -> "2G"
|
||||
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" + UNDERSCORE + mTelephonyManager.networkType
|
||||
@@ -312,9 +367,10 @@ fun getNetworkType(context: Context): String {
|
||||
|
||||
fun getCarrierName(context: Context): String? {
|
||||
return try {
|
||||
(context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager).networkOperatorName
|
||||
(context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager)
|
||||
.networkOperatorName
|
||||
} catch (e: Exception) {
|
||||
e.log()
|
||||
e.log()
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -347,7 +403,6 @@ fun getCpuUsage(): Float {
|
||||
}
|
||||
reader.close()
|
||||
return cpuUsage
|
||||
|
||||
}
|
||||
|
||||
fun getStorageUsage(context: Context): Pair<Long, Long> {
|
||||
@@ -362,7 +417,9 @@ fun getStorageUsage(context: Context): Pair<Long, Long> {
|
||||
}
|
||||
|
||||
enum class VideoQuality {
|
||||
LOW, HIGH, MEDIUM
|
||||
LOW,
|
||||
HIGH,
|
||||
MEDIUM
|
||||
}
|
||||
|
||||
private fun Any.tag(): String {
|
||||
@@ -386,8 +443,8 @@ fun isNetworkAvailable(context: Context): Boolean {
|
||||
return connectivityManager?.activeNetworkInfo?.isConnected.orFalse()
|
||||
}
|
||||
|
||||
private fun isResolutionEven(size: Int): Boolean {
|
||||
return size.mod(2) == 0
|
||||
private fun isResolutionEven(width: Int, height: Int): Boolean {
|
||||
return width.mod(2) == 0 && height.mod(2) == 0
|
||||
}
|
||||
|
||||
fun recordException(e: Throwable) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2022-2023 by Navi Technologies Limited
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
@@ -16,12 +16,11 @@ import com.navi.alfred.dispatcher.AlfredDispatcher
|
||||
import com.navi.alfred.utils.AlfredConstants
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class AddEventTask(
|
||||
private val event: AnalyticsEvent,
|
||||
private val context: Context
|
||||
) : AnalyticsTask {
|
||||
class AddEventTask(private val event: AnalyticsEvent, private val context: Context) :
|
||||
AnalyticsTask {
|
||||
companion object {
|
||||
private var eventCount: AtomicInteger = AtomicInteger(0)
|
||||
|
||||
fun resetEventCount() {
|
||||
eventCount = AtomicInteger(0)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.alfred.worker
|
||||
|
||||
import android.content.Context
|
||||
@@ -9,12 +16,11 @@ import com.navi.alfred.dispatcher.AlfredDispatcher
|
||||
import com.navi.alfred.utils.AlfredConstants
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
|
||||
class AddMetricTask(
|
||||
private val event: ApiMetricHelper, private val context: Context
|
||||
) : AnalyticsTask {
|
||||
class AddMetricTask(private val event: ApiMetricHelper, private val context: Context) :
|
||||
AnalyticsTask {
|
||||
companion object {
|
||||
private var eventCount: AtomicInteger = AtomicInteger(0)
|
||||
|
||||
fun resetEventCount() {
|
||||
eventCount = AtomicInteger(0)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2019-2023 by Navi Technologies Limited
|
||||
* * Copyright © 2021-2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
@@ -10,8 +10,7 @@ package com.navi.alfred.worker
|
||||
import androidx.annotation.WorkerThread
|
||||
|
||||
interface AnalyticsTask {
|
||||
@WorkerThread
|
||||
fun execute(): Boolean
|
||||
@WorkerThread fun execute(): Boolean
|
||||
|
||||
fun getTaskName(): String
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2019-2023 by Navi Technologies Limited
|
||||
* * Copyright © 2021-2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.alfred.worker
|
||||
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import java.util.concurrent.BlockingDeque
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.LinkedBlockingDeque
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
|
||||
class AnalyticsTaskProcessor {
|
||||
private val taskQueue: BlockingDeque<AnalyticsTask> = LinkedBlockingDeque<AnalyticsTask>()
|
||||
@@ -18,6 +18,7 @@ class AnalyticsTaskProcessor {
|
||||
private val singleThreadExecutorForSync = Executors.newSingleThreadExecutor()
|
||||
private var active: AnalyticsTask? = null
|
||||
private var isSyncEventTaskExecuted: Boolean = true
|
||||
|
||||
fun addTask(task: AnalyticsTask?) {
|
||||
if (task != null) {
|
||||
taskQueue.add(task)
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2023 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.alfred.worker
|
||||
|
||||
import android.content.Context
|
||||
@@ -14,43 +21,53 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.lang.reflect.Type
|
||||
|
||||
class UploadFileWorker(context: Context, workerParams: WorkerParameters) :
|
||||
CoroutineWorker(context, workerParams) {
|
||||
|
||||
class UploadFileWorker(
|
||||
context: Context, workerParams: WorkerParameters
|
||||
) : CoroutineWorker(context, workerParams) {
|
||||
|
||||
override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
|
||||
val alfredSessionId = inputData.getString(AlfredConstants.ALFRED_SESSION_ID)
|
||||
val sessionStartRecordingTime =
|
||||
inputData.getLong(AlfredConstants.SESSION_START_RECORDING_TIME, 0L)
|
||||
val eventStartRecordingTime =
|
||||
inputData.getLong(AlfredConstants.EVENT_START_RECORDING_TIME, 0L)
|
||||
val screenShotList = inputData.getString(AlfredConstants.SCREENSHOT_LIST)
|
||||
val listType: Type = object : TypeToken<List<ScreenShotPathHelper?>?>() {}.type
|
||||
val screenShots: List<ScreenShotPathHelper> =
|
||||
Gson().fromJson(screenShotList.toString(), listType)
|
||||
val zipFileName =
|
||||
alfredSessionId + sessionStartRecordingTime + AlfredConstants.WORKER_ZIP_FILENAME_ENDPOINT
|
||||
workFailureData.add(
|
||||
WorkManagerFailureInputData(
|
||||
alfredSessionId = alfredSessionId,
|
||||
sessionStartRecordingTime,
|
||||
eventStartRecordingTime,
|
||||
screenShots,
|
||||
id
|
||||
override suspend fun doWork(): Result =
|
||||
withContext(Dispatchers.IO) {
|
||||
val alfredSessionId = inputData.getString(AlfredConstants.ALFRED_SESSION_ID)
|
||||
val sessionStartRecordingTime =
|
||||
inputData.getLong(AlfredConstants.SESSION_START_RECORDING_TIME, 0L)
|
||||
val eventStartRecordingTime =
|
||||
inputData.getLong(AlfredConstants.EVENT_START_RECORDING_TIME, 0L)
|
||||
val screenShotList = inputData.getString(AlfredConstants.SCREENSHOT_LIST)
|
||||
val listType: Type = object : TypeToken<List<ScreenShotPathHelper?>?>() {}.type
|
||||
val screenShots: List<ScreenShotPathHelper> =
|
||||
Gson().fromJson(screenShotList.toString(), listType)
|
||||
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) {
|
||||
Result.failure()
|
||||
} else {
|
||||
AlfredManager.toZipForWorkManager(screenShots, zipFileName,sessionStartRecordingTime,alfredSessionId, eventStartRecordingTime)
|
||||
Result.success()
|
||||
try {
|
||||
if (
|
||||
alfredSessionId == null ||
|
||||
sessionStartRecordingTime == 0L ||
|
||||
eventStartRecordingTime == 0L
|
||||
) {
|
||||
Result.failure()
|
||||
} else {
|
||||
AlfredManager.toZipForWorkManager(
|
||||
screenShots,
|
||||
zipFileName,
|
||||
sessionStartRecordingTime,
|
||||
alfredSessionId,
|
||||
eventStartRecordingTime
|
||||
)
|
||||
Result.success()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Result.retry()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Result.retry()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user