Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.res.Resources
import android.media.MediaDrm
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.Uri
import android.os.Build
import android.provider.Settings
import android.provider.Settings.Secure.getString
import android.util.Log
import androidx.core.content.pm.PackageInfoCompat
import com.facebook.react.ReactActivity
Expand All @@ -21,6 +20,8 @@ import com.facebook.react.module.annotations.ReactModule
import com.sovranreactnative.SovranModule
import java.lang.Exception
import java.util.*
import java.security.MessageDigest
import java.util.UUID


enum class ConnectionType {
Expand Down Expand Up @@ -54,88 +55,118 @@ class AnalyticsReactNativeModule : ReactContextBaseJavaModule, ActivityEventList
return PackageInfoCompat.getLongVersionCode(pInfo).toString()
}

@SuppressLint("HardwareIds")
private fun getUniqueId(collectDeviceId : Boolean): String? {
if (collectDeviceId) {
return getString(reactApplicationContext.contentResolver, Settings.Secure.ANDROID_ID)
fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }

/**
* Workaround for not able to get device id on Android 10 or above using DRM API
* {@see https://stackoverflow.com/questions/58103580/android-10-imei-no-longer-available-on-api-29-looking-for-alternatives}
* {@see https://developer.android.com/training/articles/user-data-ids}
*/
private fun getUniqueId(collectDeviceId : Boolean): String? {
if (collectDeviceId) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2)
return null

val WIDEVINE_UUID = UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L)
var wvDrm: MediaDrm? = null
try {
wvDrm = MediaDrm(WIDEVINE_UUID)
val wideVineId = wvDrm.getPropertyByteArray(MediaDrm.PROPERTY_DEVICE_UNIQUE_ID)
val md = MessageDigest.getInstance("SHA-256")
md.update(wideVineId)
return md.digest().toHexString()
} catch (e: Exception) {
return null
} finally {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
wvDrm?.close()
} else {
wvDrm?.release()
}
}
return null
}
return null
}

private fun getConnectionType(context: Context): ConnectionType {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
var result: ConnectionType = ConnectionType.Unknown

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cm?.run {
cm.getNetworkCapabilities(cm.activeNetwork)?.run {
if (hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
result = ConnectionType.Wifi
} else if (hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
result = ConnectionType.Cellular
} else {
result = ConnectionType.Unknown
}
private fun getConnectionType(context: Context): ConnectionType {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
var result: ConnectionType = ConnectionType.Unknown

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cm?.run {
cm.getNetworkCapabilities(cm.activeNetwork)?.run {
if (hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
result = ConnectionType.Wifi
} else if (hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
result = ConnectionType.Cellular
} else {
result = ConnectionType.Unknown
}
}
} else {
cm?.run {
cm.activeNetworkInfo?.run {
if (type == ConnectivityManager.TYPE_WIFI) {
result = ConnectionType.Wifi
} else if (type == ConnectivityManager.TYPE_MOBILE) {
result = ConnectionType.Cellular
} else {
result = ConnectionType.Unknown
}
}
} else {
cm?.run {
cm.activeNetworkInfo?.run {
if (type == ConnectivityManager.TYPE_WIFI) {
result = ConnectionType.Wifi
} else if (type == ConnectivityManager.TYPE_MOBILE) {
result = ConnectionType.Cellular
} else {
result = ConnectionType.Unknown
}
}
}
return result
}
return result
}

@ReactMethod
fun getContextInfo(config: ReadableMap, promise: Promise) {
val appName: String = reactApplicationContext.applicationInfo.loadLabel(reactApplicationContext.packageManager).toString()
val appVersion: String = pInfo.versionName
val buildNumber = getBuildNumber()
val bundleId = reactApplicationContext.packageName
@ReactMethod
fun getContextInfo(config: ReadableMap, promise: Promise) {
val appName: String = reactApplicationContext.applicationInfo.loadLabel(reactApplicationContext.packageManager).toString()
val appVersion: String = pInfo.versionName
val buildNumber = getBuildNumber()
val bundleId = reactApplicationContext.packageName

val connectionType: ConnectionType = getConnectionType(reactApplicationContext)
val timezone: TimeZone = TimeZone.getDefault()
val currentLocale: Locale = Locale.getDefault()
val locale: String = "${currentLocale.language}-${currentLocale.country}"
val connectionType: ConnectionType = getConnectionType(reactApplicationContext)
val timezone: TimeZone = TimeZone.getDefault()
val currentLocale: Locale = Locale.getDefault()
val locale: String = "${currentLocale.language}-${currentLocale.country}"

val screenWidth = Resources.getSystem().displayMetrics.widthPixels
val screenHeight = Resources.getSystem().displayMetrics.heightPixels
val screenWidth = Resources.getSystem().displayMetrics.widthPixels
val screenHeight = Resources.getSystem().displayMetrics.heightPixels

val screenDensity = Resources.getSystem().displayMetrics.density;
val screenDensity = Resources.getSystem().displayMetrics.density;

val contextInfo: WritableMap = Arguments.createMap()
val contextInfo: WritableMap = Arguments.createMap()

contextInfo.putString("appName", appName)
contextInfo.putString("appVersion", appVersion)
contextInfo.putString("buildNumber", buildNumber)
contextInfo.putString("bundleId", bundleId)
contextInfo.putString("deviceId", getUniqueId(config.hasKey("collectDeviceId") && config.getBoolean("collectDeviceId")))
contextInfo.putString("deviceName", Build.DEVICE)
contextInfo.putString("deviceType", "android")
contextInfo.putString("manufacturer", Build.MANUFACTURER)
contextInfo.putString("model", Build.MODEL)
// generate random identifier that does not persist across installations
// use it as the fallback in case DRM API failed to generate one.
val fallbackDeviceId = UUID.randomUUID().toString()
val deviceId = getUniqueId(config.hasKey("collectDeviceId") && config.getBoolean("collectDeviceId"))?: fallbackDeviceId

contextInfo.putString("timezone", timezone.id)
contextInfo.putString("locale", locale)
contextInfo.putString("networkType", connectionType.toString().toLowerCase(currentLocale))
contextInfo.putString("appName", appName)
contextInfo.putString("appVersion", appVersion)
contextInfo.putString("buildNumber", buildNumber)
contextInfo.putString("bundleId", bundleId)
contextInfo.putString("deviceId", deviceId)
contextInfo.putString("deviceName", Build.DEVICE)
contextInfo.putString("deviceType", "android")
contextInfo.putString("manufacturer", Build.MANUFACTURER)
contextInfo.putString("model", Build.MODEL)

contextInfo.putString("osName", "Android")
contextInfo.putString("osVersion", Build.VERSION.RELEASE)
contextInfo.putString("timezone", timezone.id)
contextInfo.putString("locale", locale)
contextInfo.putString("networkType", connectionType.toString().toLowerCase(currentLocale))

contextInfo.putInt("screenWidth", screenWidth)
contextInfo.putInt("screenHeight", screenHeight)
contextInfo.putDouble("screenDensity", screenDensity.toDouble())
contextInfo.putString("osName", "Android")
contextInfo.putString("osVersion", Build.VERSION.RELEASE)

promise.resolve(contextInfo)
}
contextInfo.putInt("screenWidth", screenWidth)
contextInfo.putInt("screenHeight", screenHeight)
contextInfo.putDouble("screenDensity", screenDensity.toDouble())

promise.resolve(contextInfo)
}

fun getReferrer(activity: Activity): Uri? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
Expand Down