Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 3 additions & 0 deletions detekt_custom.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ datadog:
- "android.graphics.drawable.LayerDrawable.getDrawable(kotlin.Int):java.lang.IndexOutOfBoundsException"
- "android.net.ConnectivityManager.registerDefaultNetworkCallback(android.net.ConnectivityManager.NetworkCallback):java.lang.IllegalArgumentException,java.lang.SecurityException"
- "android.net.ConnectivityManager.unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback):java.lang.SecurityException"
- "android.provider.Settings.System.getInt(android.content.ContentResolver?, kotlin.String?):android.provider.Settings.SettingNotFoundException"
- "android.util.Base64.encodeToString(kotlin.ByteArray?, kotlin.Int):java.lang.AssertionError"
- "android.view.Choreographer.getInstance():java.lang.IllegalStateException"
- "android.view.Choreographer.postFrameCallback():java.lang.IllegalArgumentException"
Expand Down Expand Up @@ -389,6 +390,7 @@ datadog:
- "android.net.ConnectivityManager.NetworkCallback.onLost(android.net.Network)"
- "android.net.ConnectivityManager.getNetworkCapabilities(android.net.Network?)"
- "android.net.NetworkCapabilities.hasTransport(kotlin.Int)"
- "android.os.BatteryManager.getIntProperty(kotlin.Int)"
- "android.os.Bundle.get(kotlin.String?)"
- "android.os.Bundle.getString(kotlin.String?)"
- "android.os.Bundle.keySet()"
Expand All @@ -411,6 +413,7 @@ datadog:
- "android.os.SystemClock.elapsedRealtime()"
- "android.provider.Settings.Global.getUriFor(kotlin.String?)"
- "android.provider.Settings.Secure.getUriFor(kotlin.String?)"
- "android.provider.Settings.System.getUriFor(kotlin.String?)"
- "android.util.Log.e(kotlin.String?, kotlin.String)"
- "android.util.Log.e(kotlin.String?, kotlin.String?, kotlin.Throwable?)"
- "android.util.Log.getStackTraceString(kotlin.Throwable?)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ object Rum {
lastInteractionIdentifier = rumFeature.lastInteractionIdentifier,
slowFramesListener = rumFeature.slowFramesListener,
rumSessionTypeOverride = rumFeature.configuration.rumSessionTypeOverride,
accessibilitySnapshotManager = rumFeature.accessibilitySnapshotManager
accessibilitySnapshotManager = rumFeature.accessibilitySnapshotManager,
batteryInfoProvider = rumFeature.batteryInfoProvider,
displayInfoProvider = rumFeature.displayInfoProvider
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,20 @@ import com.datadog.android.rum.configuration.SlowFramesConfiguration
import com.datadog.android.rum.configuration.VitalsUpdateFrequency
import com.datadog.android.rum.internal.anr.ANRDetectorRunnable
import com.datadog.android.rum.internal.debug.UiRumDebugListener
import com.datadog.android.rum.internal.domain.InfoProvider
import com.datadog.android.rum.internal.domain.RumDataWriter
import com.datadog.android.rum.internal.domain.accessibility.AccessibilityReader
import com.datadog.android.rum.internal.domain.accessibility.AccessibilityInfo
import com.datadog.android.rum.internal.domain.accessibility.AccessibilitySnapshotManager
import com.datadog.android.rum.internal.domain.accessibility.DatadogAccessibilityReader
import com.datadog.android.rum.internal.domain.accessibility.DefaultAccessibilityReader
import com.datadog.android.rum.internal.domain.accessibility.DefaultAccessibilitySnapshotManager
import com.datadog.android.rum.internal.domain.accessibility.NoOpAccessibilityReader
import com.datadog.android.rum.internal.domain.accessibility.NoOpAccessibilitySnapshotManager
import com.datadog.android.rum.internal.domain.battery.BatteryInfo
import com.datadog.android.rum.internal.domain.battery.DefaultBatteryInfoProvider
import com.datadog.android.rum.internal.domain.battery.NoOpBatteryInfoProvider
import com.datadog.android.rum.internal.domain.display.DefaultDisplayInfoProvider
import com.datadog.android.rum.internal.domain.display.DisplayInfo
import com.datadog.android.rum.internal.domain.display.NoOpDisplayInfoProvider
import com.datadog.android.rum.internal.domain.event.RumEventMapper
import com.datadog.android.rum.internal.domain.event.RumEventMetaDeserializer
import com.datadog.android.rum.internal.domain.event.RumEventMetaSerializer
Expand Down Expand Up @@ -151,9 +158,11 @@ internal class RumFeature(
internal var initialResourceIdentifier: InitialResourceIdentifier = NoOpInitialResourceIdentifier()
internal var lastInteractionIdentifier: LastInteractionIdentifier? = NoOpLastInteractionIdentifier()
internal var slowFramesListener: SlowFramesListener? = null
internal var accessibilityReader: AccessibilityReader = NoOpAccessibilityReader()
internal var accessibilityReader: InfoProvider<AccessibilityInfo> = NoOpAccessibilityReader()
internal var accessibilitySnapshotManager: AccessibilitySnapshotManager =
NoOpAccessibilitySnapshotManager()
internal var batteryInfoProvider: InfoProvider<BatteryInfo> = NoOpBatteryInfoProvider()
internal var displayInfoProvider: InfoProvider<DisplayInfo> = NoOpDisplayInfoProvider()

private val lateCrashEventHandler by lazy { lateCrashReporterFactory(sdkCore as InternalSdkCore) }

Expand All @@ -166,8 +175,10 @@ internal class RumFeature(
this.appContext = appContext

if (configuration.collectAccessibility) {
accessibilityReader =
DatadogAccessibilityReader(applicationContext = appContext, internalLogger = sdkCore.internalLogger)
accessibilityReader = DefaultAccessibilityReader(
internalLogger = sdkCore.internalLogger,
applicationContext = appContext
)
accessibilitySnapshotManager = DefaultAccessibilitySnapshotManager(accessibilityReader)
}

Expand All @@ -193,6 +204,13 @@ internal class RumFeature(
telemetryConfigurationSampleRate = configuration.telemetryConfigurationSampleRate
backgroundEventTracking = configuration.backgroundEventTracking
trackFrustrations = configuration.trackFrustrations
batteryInfoProvider = DefaultBatteryInfoProvider(
applicationContext = appContext
)
displayInfoProvider = DefaultDisplayInfoProvider(
applicationContext = appContext,
internalLogger = sdkCore.internalLogger
)

configuration.viewTrackingStrategy?.let { viewTrackingStrategy = it }
actionTrackingStrategy = if (configuration.userActionTracking) {
Expand Down Expand Up @@ -306,17 +324,26 @@ internal class RumFeature(
vitalExecutorService = NoOpScheduledExecutorService()
sessionListener = NoOpRumSessionListener()

cleanupInfoProviders()

GlobalRumMonitor.unregister(sdkCore)
}

// endregion

private fun cleanupInfoProviders() {
if (configuration.collectAccessibility) {
accessibilityReader.cleanup()
accessibilityReader = NoOpAccessibilityReader()
accessibilitySnapshotManager = NoOpAccessibilitySnapshotManager()
}

GlobalRumMonitor.unregister(sdkCore)
batteryInfoProvider.cleanup()
batteryInfoProvider = NoOpBatteryInfoProvider()
displayInfoProvider.cleanup()
displayInfoProvider = NoOpDisplayInfoProvider()
}

// endregion

private fun createDataWriter(
configuration: Configuration,
sdkCore: InternalSdkCore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.rum.internal.domain.accessibility
package com.datadog.android.rum.internal.domain

import com.datadog.tools.annotation.NoOpImplementation
internal interface InfoData

@NoOpImplementation
internal interface AccessibilityReader {
fun getState(): Map<String, Any>
internal interface InfoProvider<T : InfoData> {
fun getState(): T
fun cleanup()
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.rum.internal.domain.accessibility

import com.datadog.android.rum.internal.domain.InfoData

/**
* Represents the accessibility settings state of the device.
*
* @property textSize The font scale factor (1.0 = normal, >1.0 = larger, <1.0 = smaller)
* @property isScreenReaderEnabled Whether touch exploration is enabled (TalkBack, etc.)
* @property isColorInversionEnabled Whether color inversion is enabled
* @property isClosedCaptioningEnabled Whether closed captions are enabled
* @property isReducedAnimationsEnabled Whether animations are disabled/reduced
* @property isScreenPinningEnabled Whether the device is in single-app mode
* @property isRtlEnabled Whether right to left layout is enabled
*/
internal data class AccessibilityInfo(
val textSize: String? = null,
val isScreenReaderEnabled: Boolean? = null,
val isColorInversionEnabled: Boolean? = null,
val isClosedCaptioningEnabled: Boolean? = null,
val isReducedAnimationsEnabled: Boolean? = null,
val isScreenPinningEnabled: Boolean? = null,
val isRtlEnabled: Boolean? = null
) : InfoData
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ import com.datadog.tools.annotation.NoOpImplementation

@NoOpImplementation
internal interface AccessibilitySnapshotManager {
fun latestSnapshot(): Accessibility
fun latestSnapshot(): AccessibilityInfo
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ import android.view.View
import android.view.accessibility.AccessibilityManager
import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
import com.datadog.android.api.InternalLogger
import java.util.concurrent.atomic.AtomicBoolean
import com.datadog.android.rum.internal.domain.InfoProvider
import java.util.concurrent.atomic.AtomicLong

@Suppress("TooManyFunctions")
internal class DatadogAccessibilityReader(
internal class DefaultAccessibilityReader(
private val internalLogger: InternalLogger,
private val applicationContext: Context,
private val resources: Resources = applicationContext.resources,
Expand All @@ -37,14 +37,7 @@ internal class DatadogAccessibilityReader(
private val secureWrapper: SecureWrapper = SecureWrapper(),
private val globalWrapper: GlobalWrapper = GlobalWrapper(),
private val handler: Handler = Handler(Looper.getMainLooper())
) : AccessibilityReader, ComponentCallbacks {

@Volatile
private var currentState = Accessibility()

private var lastPollTime: AtomicLong = AtomicLong(0)

private var isInitialized = AtomicBoolean(false)
) : InfoProvider<AccessibilityInfo>, ComponentCallbacks {

private val displayInversionListener = object : ContentObserver(handler) {
override fun onChange(selfChange: Boolean, uri: Uri?) {
Expand Down Expand Up @@ -72,15 +65,22 @@ internal class DatadogAccessibilityReader(
updateState { it.copy(isScreenReaderEnabled = newScreenReaderEnabled) }
}

@Volatile
private var currentState = AccessibilityInfo()

private var lastPollTime: AtomicLong = AtomicLong(0)

init {
registerListeners()
buildInitialState()
}

override fun cleanup() {
if (isInitialized.get()) {
accessibilityManager?.removeTouchExplorationStateChangeListener(touchListener)
applicationContext.contentResolver.unregisterContentObserver(animationDurationListener)
applicationContext.contentResolver.unregisterContentObserver(captioningListener)
applicationContext.contentResolver.unregisterContentObserver(displayInversionListener)
applicationContext.unregisterComponentCallbacks(this)
isInitialized.set(false)
}
accessibilityManager?.removeTouchExplorationStateChangeListener(touchListener)
applicationContext.contentResolver.unregisterContentObserver(animationDurationListener)
applicationContext.contentResolver.unregisterContentObserver(captioningListener)
applicationContext.contentResolver.unregisterContentObserver(displayInversionListener)
applicationContext.unregisterComponentCallbacks(this)
}

override fun onLowMemory() {
Expand All @@ -96,34 +96,24 @@ internal class DatadogAccessibilityReader(
}

@Synchronized
override fun getState(): Map<String, Any> {
ensureInitialized()

override fun getState(): AccessibilityInfo {
val currentTime = System.currentTimeMillis()
val shouldPoll = currentTime - lastPollTime.get() >= POLL_THRESHOLD
if (shouldPoll) {
lastPollTime.set(currentTime)
pollForAttributesWithoutListeners()
}

return currentState.toMap()
return currentState
}

@Synchronized
private fun updateState(updater: (Accessibility) -> Accessibility) {
private fun updateState(updater: (AccessibilityInfo) -> AccessibilityInfo) {
currentState = updater(currentState)
}

private fun ensureInitialized() {
if (!isInitialized.get()) {
registerListeners()
currentState = buildInitialState()
isInitialized.set(true)
}
}

private fun buildInitialState(): Accessibility {
return Accessibility(
private fun buildInitialState() {
currentState = AccessibilityInfo(
textSize = getTextSize(),
isScreenReaderEnabled = isScreenReaderEnabled(accessibilityManager),
isColorInversionEnabled = isDisplayInversionEnabled(),
Expand Down Expand Up @@ -159,11 +149,11 @@ internal class DatadogAccessibilityReader(
}

private fun isDisplayInversionEnabled(): Boolean? {
return getSecureInt(ACCESSIBILITY_DISPLAY_INVERSION_ENABLED)
return isSettingEnabled(ACCESSIBILITY_DISPLAY_INVERSION_ENABLED)
}

private fun isClosedCaptioningEnabled(): Boolean? {
return getSecureInt(CAPTIONING_ENABLED_KEY)
return isSettingEnabled(CAPTIONING_ENABLED_KEY)
}

private fun isLockToScreenEnabled(): Boolean? {
Expand All @@ -187,12 +177,14 @@ internal class DatadogAccessibilityReader(
}
}

private fun getSecureInt(key: String): Boolean? {
private fun isSettingEnabled(key: String): Boolean? {
return secureWrapper.getInt(
internalLogger = internalLogger,
applicationContext = applicationContext,
key = key
)
)?.let {
it == 1
}
}

private fun getTextSize(): String {
Expand Down
Loading
Loading