1
+ package com.aheaditec.freerasp
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.app.Activity
5
+ import android.app.Activity.ScreenCaptureCallback
6
+ import android.content.Context
7
+ import android.content.pm.PackageManager
8
+ import android.os.Build
9
+ import android.view.WindowManager.SCREEN_RECORDING_STATE_VISIBLE
10
+ import androidx.annotation.RequiresApi
11
+ import androidx.core.content.ContextCompat
12
+ import androidx.lifecycle.DefaultLifecycleObserver
13
+ import androidx.lifecycle.LifecycleOwner
14
+ import com.aheaditec.talsec_security.security.api.Talsec
15
+ import io.flutter.Log
16
+ import java.util.function.Consumer
17
+
18
+ internal class ScreenProtector : DefaultLifecycleObserver {
19
+ companion object {
20
+ private const val TAG = " ScreenProtector"
21
+ private const val SCREEN_CAPTURE_PERMISSION = " android.permission.DETECT_SCREEN_CAPTURE"
22
+ private const val SCREEN_RECORDING_PERMISSION = " android.permission.DETECT_SCREEN_RECORDING"
23
+ }
24
+
25
+ internal var activity: Activity ? = null
26
+ private var isEnabled = false
27
+
28
+ private val screenCaptureCallback = ScreenCaptureCallback { Talsec .onScreenshotDetected() }
29
+ private val screenRecordCallback: Consumer <Int > = Consumer <Int > { state ->
30
+ if (state == SCREEN_RECORDING_STATE_VISIBLE ) {
31
+ Talsec .onScreenRecordingDetected()
32
+ Log .e(" ScreenProtector" , " Screen recording detected" )
33
+ }
34
+ }
35
+
36
+ internal fun enable () {
37
+ if (isEnabled) return
38
+ isEnabled = true
39
+ }
40
+
41
+ override fun onStart (owner : LifecycleOwner ) {
42
+ super .onStart(owner)
43
+
44
+ if (isEnabled) activity?.let { register(it) }
45
+ }
46
+
47
+ override fun onStop (owner : LifecycleOwner ) {
48
+ super .onStop(owner)
49
+
50
+ if (isEnabled) activity?.let { unregister(it) }
51
+ }
52
+
53
+ private fun register (activity : Activity ) {
54
+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .UPSIDE_DOWN_CAKE ) {
55
+ registerScreenCapture(activity)
56
+ }
57
+
58
+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .VANILLA_ICE_CREAM ) {
59
+ registerScreenRecording(activity)
60
+ }
61
+ }
62
+
63
+ // Missing permission is suppressed because the decision to use the screen capture API is made
64
+ // by developer, and not enforced by the library.
65
+ @SuppressLint(" MissingPermission" )
66
+ private fun unregister (currentActivity : Activity ) {
67
+ val context = currentActivity.applicationContext
68
+
69
+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .UPSIDE_DOWN_CAKE && hasPermission(
70
+ context, SCREEN_CAPTURE_PERMISSION
71
+ )
72
+ ) {
73
+ currentActivity.unregisterScreenCaptureCallback(screenCaptureCallback)
74
+ }
75
+
76
+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .VANILLA_ICE_CREAM && hasPermission(
77
+ context, SCREEN_RECORDING_PERMISSION
78
+ )
79
+ ) {
80
+ currentActivity.windowManager?.removeScreenRecordingCallback(screenRecordCallback)
81
+ }
82
+ }
83
+
84
+ // Missing permission is suppressed because the decision to use the screen capture API is made
85
+ // by developer, and not enforced by the library.
86
+ @SuppressLint(" MissingPermission" )
87
+ @RequiresApi(Build .VERSION_CODES .UPSIDE_DOWN_CAKE )
88
+ private fun registerScreenCapture (currentActivity : Activity ) {
89
+ val context = currentActivity.applicationContext
90
+
91
+ if (! hasPermission(context, SCREEN_CAPTURE_PERMISSION )) {
92
+ reportMissingPermission(" screenshot" , SCREEN_CAPTURE_PERMISSION )
93
+ return
94
+ }
95
+
96
+ currentActivity.registerScreenCaptureCallback(context.mainExecutor, screenCaptureCallback)
97
+ }
98
+
99
+ // Missing permission is suppressed because the decision to use the screen capture API is made
100
+ // by developer, and not enforced by the library.
101
+ @SuppressLint(" MissingPermission" )
102
+ @RequiresApi(Build .VERSION_CODES .VANILLA_ICE_CREAM )
103
+ private fun registerScreenRecording (currentActivity : Activity ) {
104
+ val context = currentActivity.applicationContext
105
+
106
+ if (! hasPermission(context, SCREEN_RECORDING_PERMISSION )) {
107
+ reportMissingPermission(" screen record" , SCREEN_RECORDING_PERMISSION )
108
+ return
109
+ }
110
+
111
+ val initialState = currentActivity.windowManager.addScreenRecordingCallback(
112
+ context.mainExecutor, screenRecordCallback
113
+ )
114
+ screenRecordCallback.accept(initialState)
115
+
116
+ }
117
+
118
+ private fun hasPermission (context : Context , permission : String ): Boolean {
119
+ return ContextCompat .checkSelfPermission(
120
+ context, permission
121
+ ) == PackageManager .PERMISSION_GRANTED
122
+ }
123
+
124
+ private fun reportMissingPermission (protectionType : String , permission : String ) {
125
+ Log .e(
126
+ TAG ,
127
+ " Failed to register $protectionType callback. Check if $permission permission is granted in AndroidManifest.xml"
128
+ )
129
+ }
130
+ }
0 commit comments