Skip to content

Commit fc39b65

Browse files
authored
Merge pull request #2787 from DataDog/jmoskovich/rum-9631/accessibility-attributes
RUM-9631: Add accessibility attributes
2 parents f07455b + 971e7fe commit fc39b65

29 files changed

+1451
-55
lines changed

detekt_custom.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ datadog:
369369
- "android.content.Context.registerReceiver(android.content.BroadcastReceiver?, android.content.IntentFilter?)"
370370
- "android.content.Context.registerReceiver(android.content.BroadcastReceiver?, android.content.IntentFilter?, kotlin.Int)"
371371
- "android.content.Context.resourceIdName(kotlin.Int)"
372+
- "android.content.Context.unregisterComponentCallbacks(android.content.ComponentCallbacks?)"
372373
- "android.content.Context.unregisterReceiver(android.content.BroadcastReceiver?)"
373374
- "android.content.Intent.getBooleanExtra(kotlin.String?, kotlin.Boolean)"
374375
- "android.content.Intent.getIntExtra(kotlin.String?, kotlin.Int)"
@@ -406,12 +407,17 @@ datadog:
406407
- "android.os.StrictMode.allowThreadDiskWrites()"
407408
- "android.os.StrictMode.setThreadPolicy(android.os.StrictMode.ThreadPolicy?)"
408409
- "android.os.SystemClock.elapsedRealtime()"
410+
- "android.provider.Settings.Global.getUriFor(kotlin.String?)"
411+
- "android.provider.Settings.Secure.getUriFor(kotlin.String?)"
409412
- "android.util.Log.e(kotlin.String?, kotlin.String)"
410413
- "android.util.Log.e(kotlin.String?, kotlin.String?, kotlin.Throwable?)"
411414
- "android.util.Log.getStackTraceString(kotlin.Throwable?)"
412415
- "android.util.Log.i(kotlin.String?, kotlin.String)"
413416
- "android.util.Log.w(kotlin.String?, kotlin.String)"
414417
- "android.util.TypedValue.constructor()"
418+
- "android.view.accessibility.AccessibilityManager.addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener)"
419+
- "android.view.accessibility.AccessibilityManager.removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener)"
420+
- "android.view.accessibility.TouchExplorationStateChangeListener(kotlin.Function1)"
415421
- "android.view.Choreographer.postFrameCallback(android.view.Choreographer.FrameCallback)"
416422
- "android.view.Display.getSize(android.graphics.Point?)"
417423
- "android.view.FrameMetrics.getMetric(kotlin.Int)"
@@ -554,6 +560,8 @@ datadog:
554560
- "androidx.compose.ui.semantics.SemanticsConfiguration.getOrNull(androidx.compose.ui.semantics.SemanticsPropertyKey)"
555561
- "androidx.compose.ui.semantics.SemanticsPropertyKey.constructor(kotlin.String, kotlin.Function2)"
556562
- "androidx.compose.ui.text.AnnotatedString.getStringAnnotations(kotlin.Int, kotlin.Int)"
563+
- "android.content.ContentResolver.registerContentObserver(android.net.Uri, kotlin.Boolean, android.database.ContentObserver)"
564+
- "android.content.ContentResolver.unregisterContentObserver(android.database.ContentObserver)"
557565
- "androidx.core.view.GestureDetectorCompat.constructor(android.content.Context, android.view.GestureDetector.OnGestureListener)"
558566
- "androidx.core.view.GestureDetectorCompat.onTouchEvent(android.view.MotionEvent)"
559567
- "androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks.onFragmentActivityCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?)"

features/dd-sdk-android-rum/api/apiSurface

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ class com.datadog.android.rum._RumInternalProxy
174174
fun setAdditionalConfiguration(com.datadog.android.rum.RumConfiguration.Builder, Map<String, Any>): com.datadog.android.rum.RumConfiguration.Builder
175175
fun setComposeActionTrackingStrategy(com.datadog.android.rum.RumConfiguration.Builder, com.datadog.android.rum.tracking.ActionTrackingStrategy): com.datadog.android.rum.RumConfiguration.Builder
176176
fun setRumSessionTypeOverride(com.datadog.android.rum.RumConfiguration.Builder, RumSessionType): com.datadog.android.rum.RumConfiguration.Builder
177+
fun collectAccessibilitySettings(com.datadog.android.rum.RumConfiguration.Builder): com.datadog.android.rum.RumConfiguration.Builder
177178
data class com.datadog.android.rum.configuration.SlowFramesConfiguration
178179
constructor(Int = DEFAULT_SLOW_FRAME_RECORDS_MAX_AMOUNT, Long = DEFAULT_FROZEN_FRAME_THRESHOLD_NS, Long = DEFAULT_CONTINUOUS_SLOW_FRAME_THRESHOLD_NS, Long = DEFAULT_FREEZE_DURATION_NS, Long = DEFAULT_VIEW_LIFETIME_THRESHOLD_NS)
179180
companion object

features/dd-sdk-android-rum/api/dd-sdk-android-rum.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ public final class com/datadog/android/rum/_RumInternalProxy {
253253
}
254254

255255
public final class com/datadog/android/rum/_RumInternalProxy$Companion {
256+
public final fun collectAccessibilitySettings (Lcom/datadog/android/rum/RumConfiguration$Builder;)Lcom/datadog/android/rum/RumConfiguration$Builder;
256257
public final fun setAdditionalConfiguration (Lcom/datadog/android/rum/RumConfiguration$Builder;Ljava/util/Map;)Lcom/datadog/android/rum/RumConfiguration$Builder;
257258
public final fun setComposeActionTrackingStrategy (Lcom/datadog/android/rum/RumConfiguration$Builder;Lcom/datadog/android/rum/tracking/ActionTrackingStrategy;)Lcom/datadog/android/rum/RumConfiguration$Builder;
258259
public final fun setRumSessionTypeOverride (Lcom/datadog/android/rum/RumConfiguration$Builder;Lcom/datadog/android/rum/RumSessionType;)Lcom/datadog/android/rum/RumConfiguration$Builder;

features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/Rum.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ object Rum {
140140
initialResourceIdentifier = rumFeature.initialResourceIdentifier,
141141
lastInteractionIdentifier = rumFeature.lastInteractionIdentifier,
142142
slowFramesListener = rumFeature.slowFramesListener,
143-
rumSessionTypeOverride = rumFeature.configuration.rumSessionTypeOverride
143+
rumSessionTypeOverride = rumFeature.configuration.rumSessionTypeOverride,
144+
accessibilityReader = rumFeature.accessibilityReader
144145
)
145146
}
146147

features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/RumConfiguration.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,15 @@ data class RumConfiguration internal constructor(
387387
rumConfig = rumConfig.copy(rumSessionTypeOverride = rumSessionTypeOverride)
388388
return this
389389
}
390+
391+
/**
392+
* Sets a flag to collect accessibility settings inside the RUM view end event.
393+
* By default these settings are not collected.
394+
*/
395+
internal fun collectAccessibilitySettings(): Builder {
396+
rumConfig = rumConfig.copy(collectAccessibilitySettings = true)
397+
return this
398+
}
390399
// endregion
391400
}
392401
}

features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/_RumInternalProxy.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,11 @@ class _RumInternalProxy internal constructor(private val rumMonitor: AdvancedRum
115115
): Builder {
116116
return builder.setRumSessionTypeOverride(rumSessionTypeOverride)
117117
}
118+
119+
fun collectAccessibilitySettings(
120+
builder: Builder
121+
): Builder {
122+
return builder.collectAccessibilitySettings()
123+
}
118124
}
119125
}

features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/RumFeature.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ import com.datadog.android.rum.configuration.VitalsUpdateFrequency
4343
import com.datadog.android.rum.internal.anr.ANRDetectorRunnable
4444
import com.datadog.android.rum.internal.debug.UiRumDebugListener
4545
import com.datadog.android.rum.internal.domain.RumDataWriter
46+
import com.datadog.android.rum.internal.domain.accessibility.AccessibilityReader
47+
import com.datadog.android.rum.internal.domain.accessibility.DatadogAccessibilityReader
48+
import com.datadog.android.rum.internal.domain.accessibility.NoOpAccessibilityReader
4649
import com.datadog.android.rum.internal.domain.event.RumEventMapper
4750
import com.datadog.android.rum.internal.domain.event.RumEventMetaDeserializer
4851
import com.datadog.android.rum.internal.domain.event.RumEventMetaSerializer
@@ -145,15 +148,23 @@ internal class RumFeature(
145148
internal var initialResourceIdentifier: InitialResourceIdentifier = NoOpInitialResourceIdentifier()
146149
internal var lastInteractionIdentifier: LastInteractionIdentifier? = NoOpLastInteractionIdentifier()
147150
internal var slowFramesListener: SlowFramesListener? = null
151+
internal var accessibilityReader: AccessibilityReader = NoOpAccessibilityReader()
148152

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

151155
// region Feature
152156

153157
override val name: String = Feature.RUM_FEATURE_NAME
154158

159+
@Suppress("LongMethod")
155160
override fun onInitialize(appContext: Context) {
156161
this.appContext = appContext
162+
163+
if (configuration.collectAccessibilitySettings) {
164+
accessibilityReader =
165+
DatadogAccessibilityReader(applicationContext = appContext, internalLogger = sdkCore.internalLogger)
166+
}
167+
157168
initialResourceIdentifier = configuration.initialResourceIdentifier
158169
lastInteractionIdentifier = configuration.lastInteractionIdentifier
159170

@@ -288,6 +299,7 @@ internal class RumFeature(
288299
anrDetectorRunnable?.stop()
289300
vitalExecutorService = NoOpScheduledExecutorService()
290301
sessionListener = NoOpRumSessionListener()
302+
accessibilityReader.cleanup()
291303

292304
GlobalRumMonitor.unregister(sdkCore)
293305
}
@@ -630,7 +642,8 @@ internal class RumFeature(
630642
val composeActionTrackingStrategy: ActionTrackingStrategy,
631643
val additionalConfig: Map<String, Any>,
632644
val trackAnonymousUser: Boolean,
633-
val rumSessionTypeOverride: RumSessionType?
645+
val rumSessionTypeOverride: RumSessionType?,
646+
val collectAccessibilitySettings: Boolean
634647
)
635648

636649
internal companion object {
@@ -680,7 +693,8 @@ internal class RumFeature(
680693
additionalConfig = emptyMap(),
681694
trackAnonymousUser = true,
682695
slowFramesConfiguration = null,
683-
rumSessionTypeOverride = null
696+
rumSessionTypeOverride = null,
697+
collectAccessibilitySettings = false
684698
)
685699

686700
internal const val EVENT_MESSAGE_PROPERTY = "message"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2016-Present Datadog, Inc.
5+
*/
6+
7+
package com.datadog.android.rum.internal.domain.accessibility
8+
9+
/**
10+
* Represents the accessibility settings state of the device.
11+
*
12+
* @property textSize The font scale factor (1.0 = normal, >1.0 = larger, <1.0 = smaller)
13+
* @property isScreenReaderEnabled Whether touch exploration is enabled (TalkBack, etc.)
14+
* @property isColorInversionEnabled Whether color inversion is enabled
15+
* @property isClosedCaptioningEnabled Whether closed captions are enabled
16+
* @property isReducedAnimationsEnabled Whether animations are disabled/reduced
17+
* @property isScreenPinningEnabled Whether the device is in single-app mode
18+
*/
19+
internal data class Accessibility(
20+
val textSize: Float? = null,
21+
val isScreenReaderEnabled: Boolean? = null,
22+
val isColorInversionEnabled: Boolean? = null,
23+
val isClosedCaptioningEnabled: Boolean? = null,
24+
val isReducedAnimationsEnabled: Boolean? = null,
25+
val isScreenPinningEnabled: Boolean? = null
26+
) {
27+
fun toMap(): Map<String, Any> = buildMap {
28+
textSize?.let { put(TEXT_SIZE_KEY, it) }
29+
isScreenReaderEnabled?.let { put(SCREEN_READER_ENABLED_KEY, it) }
30+
isColorInversionEnabled?.let { put(COLOR_INVERSION_ENABLED_KEY, it) }
31+
isClosedCaptioningEnabled?.let { put(CLOSED_CAPTIONING_ENABLED_KEY, it) }
32+
isReducedAnimationsEnabled?.let { put(REDUCED_ANIMATIONS_ENABLED_KEY, it) }
33+
isScreenPinningEnabled?.let { put(SCREEN_PINNING_ENABLED_KEY, it) }
34+
}
35+
36+
companion object {
37+
internal const val TEXT_SIZE_KEY = "text_size"
38+
internal const val SCREEN_READER_ENABLED_KEY = "screen_reader_enabled"
39+
internal const val COLOR_INVERSION_ENABLED_KEY = "invert_colors_enabled"
40+
internal const val CLOSED_CAPTIONING_ENABLED_KEY = "closed_captioning_enabled"
41+
internal const val REDUCED_ANIMATIONS_ENABLED_KEY = "reduced_animations_enabled"
42+
internal const val SCREEN_PINNING_ENABLED_KEY = "single_app_mode_enabled"
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2016-Present Datadog, Inc.
5+
*/
6+
7+
package com.datadog.android.rum.internal.domain.accessibility
8+
9+
import com.datadog.tools.annotation.NoOpImplementation
10+
11+
@NoOpImplementation
12+
internal interface AccessibilityReader {
13+
fun getState(): Map<String, Any>
14+
15+
fun cleanup()
16+
17+
companion object {
18+
internal const val ACCESSIBILITY_KEY = "accessibility"
19+
}
20+
}

0 commit comments

Comments
 (0)