Coverage Summary for Class: ApplicationStateMonitor (dev.shreyaspatil.permissionFlow.internal)
Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
ApplicationStateMonitor |
100%
(6/6)
|
83.3%
(5/6)
|
100%
(11/11)
|
100%
(52/52)
|
ApplicationStateMonitor$activityForegroundEvents$1 |
100%
(2/2)
|
|
100%
(6/6)
|
100%
(37/37)
|
ApplicationStateMonitor$activityForegroundEvents$1$callback$1 |
90%
(9/10)
|
92.3%
(24/26)
|
95.2%
(20/21)
|
97.5%
(119/122)
|
Total |
94.4%
(17/18)
|
90.6%
(29/32)
|
97.4%
(37/38)
|
98.6%
(208/211)
|
1
16 package dev.shreyaspatil.permissionFlow.internal
17
18 import android.app.Activity
19 import android.app.Application
20 import android.content.pm.PackageManager
21 import android.os.Build
22 import android.os.Bundle
23 import androidx.annotation.RequiresApi
24 import androidx.annotation.VisibleForTesting
25 import androidx.core.app.ActivityCompat
26 import androidx.core.content.ContextCompat
27 import dev.shreyaspatil.permissionFlow.PermissionState
28 import java.lang.ref.WeakReference
29 import kotlinx.coroutines.channels.awaitClose
30 import kotlinx.coroutines.flow.callbackFlow
31
32 /**
33 * Monitors the state of the application and provides information about the info and state of
34 * application.
35 */
36 internal class ApplicationStateMonitor(private val application: Application) {
37 private var currentActivity: WeakReference<Activity>? = null
38
39
40 fun getPermissionState(permission: String): PermissionState {
41 val isGranted = isPermissionGranted(permission)
42 val isRationaleRequired = shouldShowPermissionRationale(permission)
43 return PermissionState(permission, isGranted, isRationaleRequired)
44 }
45
46
47 private fun shouldShowPermissionRationale(permission: String): Boolean? {
48 val activity = currentActivity?.get() ?: return null
49 return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)
50 }
51
52
53 private fun isPermissionGranted(permission: String): Boolean {
54 return ContextCompat.checkSelfPermission(
55 application,
56 permission,
57 ) == PackageManager.PERMISSION_GRANTED
58 }
59
60
65 val activityForegroundEvents
66 get() = callbackFlow {
67 val callback =
68 object : Application.ActivityLifecycleCallbacks {
69 private var isActivityChangingConfigurations: Boolean? = null
70 private var wasInMultiWindowMode: Boolean? = null
71 private var wasInPictureInPictureMode: Boolean? = null
72
73 override fun onActivityPreCreated(
74 activity: Activity,
75 savedInstanceState: Bundle?,
76 ) {
77 currentActivity = WeakReference(activity)
78 }
79
80 override fun onActivityCreated(
81 activity: Activity,
82 savedInstanceState: Bundle?,
83 ) {
84 if (currentActivity?.get() != activity) {
85 currentActivity = WeakReference(activity)
86 }
87 }
88
89
93 override fun onActivityStarted(activity: Activity) {
94 if (isActivityChangingConfigurations == false) {
95 trySend(Unit)
96 }
97 }
98
99 override fun onActivityStopped(activity: Activity) {
100 isActivityChangingConfigurations = activity.isChangingConfigurations
101 }
102
103
111 override fun onActivityResumed(activity: Activity) {
112 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
113 if (isActivityResumedAfterMultiWindowOrPiPMode(activity)) {
114 trySend(Unit)
115 }
116 wasInMultiWindowMode = activity.isInMultiWindowMode
117 wasInPictureInPictureMode = activity.isInPictureInPictureMode
118 }
119 }
120
121
125 override fun onActivityPaused(activity: Activity) {
126 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
127 wasInMultiWindowMode = activity.isInMultiWindowMode
128 wasInPictureInPictureMode = activity.isInPictureInPictureMode
129 }
130 }
131
132 override fun onActivitySaveInstanceState(
133 activity: Activity,
134 outState: Bundle,
135 ) {}
136
137 override fun onActivityDestroyed(activity: Activity) {
138 if (activity == currentActivity?.get()) {
139 currentActivity?.clear()
140 }
141 }
142
143
146 @RequiresApi(Build.VERSION_CODES.N)
147 private fun isActivityResumedAfterMultiWindowOrPiPMode(activity: Activity) =
148 (wasInMultiWindowMode == true && !activity.isInMultiWindowMode) ||
149 (wasInPictureInPictureMode == true &&
150 !activity.isInPictureInPictureMode)
151 }
152
153 application.registerActivityLifecycleCallbacks(callback)
154
155 awaitClose {
156
157 application.unregisterActivityLifecycleCallbacks(callback)
158 }
159 }
160
161 @VisibleForTesting fun getCurrentActivityReference() = currentActivity
162 }