Skip to content

Commit 4912bc6

Browse files
authored
Merge pull request #2701 from DataDog/nogorodnikov/rum-10269/fix-npe-in-isOnSecondaryDisplay-method
RUM-10269: Fix `NullPointerException` in `isOnSecondaryDisplay` method
2 parents a7e439e + 644df81 commit 4912bc6

File tree

2 files changed

+51
-6
lines changed

2 files changed

+51
-6
lines changed

features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/ViewUtilsInternal.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package com.datadog.android.sessionreplay.internal.recorder
88

99
import android.annotation.SuppressLint
1010
import android.graphics.drawable.Drawable
11+
import android.os.Build
1112
import android.view.Display
1213
import android.view.View
1314
import android.view.ViewStub
@@ -32,8 +33,16 @@ internal class ViewUtilsInternal {
3233
return view.id in systemViewIds || view is ViewStub || view is ActionBarContextView
3334
}
3435

35-
internal fun isOnSecondaryDisplay(view: View): Boolean =
36-
view.display.displayId != Display.DEFAULT_DISPLAY
36+
internal fun isOnSecondaryDisplay(view: View): Boolean {
37+
val display = view.display
38+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
39+
display != null &&
40+
display.displayId != Display.DEFAULT_DISPLAY &&
41+
display.displayId != Display.INVALID_DISPLAY
42+
} else {
43+
display != null && display.displayId != Display.DEFAULT_DISPLAY
44+
}
45+
}
3746

3847
@Suppress("UnsafeThirdPartyFunctionCall") // NPE cannot happen here
3948
internal fun isToolbar(view: View): Boolean {

features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/ViewUtilsInternalTest.kt

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package com.datadog.android.sessionreplay.internal.recorder
88

99
import android.graphics.drawable.Drawable
10+
import android.os.Build
1011
import android.view.Display
1112
import android.view.View
1213
import android.view.ViewStub
@@ -15,6 +16,7 @@ import androidx.appcompat.widget.ActionBarContextView
1516
import androidx.appcompat.widget.Toolbar
1617
import com.datadog.android.sessionreplay.forge.ForgeConfigurator
1718
import com.datadog.android.sessionreplay.internal.recorder.resources.DefaultImageWireframeHelper
19+
import com.datadog.tools.unit.annotations.TestTargetApi
1820
import com.datadog.tools.unit.extensions.ApiLevelExtension
1921
import fr.xgouchet.elmyr.Forge
2022
import fr.xgouchet.elmyr.annotation.IntForgery
@@ -28,6 +30,7 @@ import org.junit.jupiter.api.extension.Extensions
2830
import org.mockito.Mock
2931
import org.mockito.junit.jupiter.MockitoExtension
3032
import org.mockito.junit.jupiter.MockitoSettings
33+
import org.mockito.kotlin.doReturn
3134
import org.mockito.kotlin.mock
3235
import org.mockito.kotlin.whenever
3336
import org.mockito.quality.Strictness
@@ -337,8 +340,9 @@ internal class ViewUtilsInternalTest {
337340
@IntForgery(min = Display.DEFAULT_DISPLAY + 1) fakeDisplayId: Int
338341
) {
339342
// Given
340-
whenever(mockView.display).thenReturn(mock())
341-
whenever(mockView.display?.displayId).thenReturn(fakeDisplayId)
343+
val mockDisplay = mock<Display>()
344+
whenever(mockView.display) doReturn mockDisplay
345+
whenever(mockDisplay.displayId) doReturn fakeDisplayId
342346

343347
// When
344348
val isOnSecondaryDisplay = testViewUtilsInternal.isOnSecondaryDisplay(mockView)
@@ -352,8 +356,40 @@ internal class ViewUtilsInternalTest {
352356
@Mock mockView: View
353357
) {
354358
// Given
355-
whenever(mockView.display).thenReturn(mock())
356-
whenever(mockView.display?.displayId).thenReturn(Display.DEFAULT_DISPLAY)
359+
val mockDisplay = mock<Display>()
360+
whenever(mockView.display) doReturn mockDisplay
361+
whenever(mockDisplay.displayId) doReturn Display.DEFAULT_DISPLAY
362+
363+
// When
364+
val isOnSecondaryDisplay = testViewUtilsInternal.isOnSecondaryDisplay(mockView)
365+
366+
// Then
367+
assertThat(isOnSecondaryDisplay).isFalse
368+
}
369+
370+
@Test
371+
@TestTargetApi(Build.VERSION_CODES.M)
372+
fun `M return false W isOnSecondaryDisplay { invalid display }`(
373+
@Mock mockView: View
374+
) {
375+
// Given
376+
val mockDisplay = mock<Display>()
377+
whenever(mockView.display) doReturn mockDisplay
378+
whenever(mockDisplay.displayId) doReturn Display.INVALID_DISPLAY
379+
380+
// When
381+
val isOnSecondaryDisplay = testViewUtilsInternal.isOnSecondaryDisplay(mockView)
382+
383+
// Then
384+
assertThat(isOnSecondaryDisplay).isFalse
385+
}
386+
387+
@Test
388+
fun `M return false W isOnSecondaryDisplay { no display }`(
389+
@Mock mockView: View
390+
) {
391+
// Given
392+
whenever(mockView.display) doReturn null
357393

358394
// When
359395
val isOnSecondaryDisplay = testViewUtilsInternal.isOnSecondaryDisplay(mockView)

0 commit comments

Comments
 (0)