Coverage Summary for Class: ActivityLifecycleCallbackExtKt (dev.shreyaspatil.permissionFlow.utils)
Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
ActivityLifecycleCallbackExtKt |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(7/7)
|
ActivityLifecycleCallbackExtKt$activityForegroundEventFlow$1 |
100%
(1/1)
|
|
100%
(4/4)
|
100%
(32/32)
|
ActivityLifecycleCallbackExtKt$activityForegroundEventFlow$1$1 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(6/6)
|
ActivityLifecycleCallbackExtKt$activityForegroundEventFlow$1$callback$1 |
66.7%
(6/9)
|
87.5%
(14/16)
|
82.4%
(14/17)
|
100%
(74/74)
|
Total |
75%
(9/12)
|
87.5%
(14/16)
|
87%
(20/23)
|
100%
(119/119)
|
1 /**
2 * Copyright 2022 Shreyas Patil
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package dev.shreyaspatil.permissionFlow.utils
17
18 import android.app.Activity
19 import android.app.Application
20 import android.os.Build
21 import android.os.Bundle
22 import androidx.annotation.RequiresApi
23 import kotlinx.coroutines.channels.awaitClose
24 import kotlinx.coroutines.flow.callbackFlow
25
26 /**
27 * A flow which gives callback whenever any activity is started withing application (without
28 * configuration change) or any activity is resumed after being in multi-window or
29 * picture-in-picture mode.
30 */
31 internal val Application.activityForegroundEventFlow
32 get() = callbackFlow {
33 val callback = object : Application.ActivityLifecycleCallbacks {
34 private var isActivityChangingConfigurations: Boolean? = null
35 private var wasInMultiWindowMode: Boolean? = null
36 private var wasInPictureInPictureMode: Boolean? = null
37
38 /**
39 * Whenever activity receives onStart() lifecycle callback, emit foreground event only
40 * when activity hasn't changed configurations.
41 */
42 override fun onActivityStarted(activity: Activity) {
43 if (isActivityChangingConfigurations == false) {
44 trySend(Unit)
45 }
46 }
47
48 override fun onActivityStopped(activity: Activity) {
49 isActivityChangingConfigurations = activity.isChangingConfigurations
50 }
51
52 override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
53
54 /**
55 * Whenever application is resized after being in in PiP or multi-window mode, or exits
56 * from these modes, onResumed() lifecycle callback is triggered.
57 *
58 * Here we assume that user has changed permission from app settings after being in
59 * PiP or multi-window mode. So whenever these modes are exited, emit foreground event.
60 */
61 override fun onActivityResumed(activity: Activity) {
62 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
63 if (isActivityResumedAfterMultiWindowOrPiPMode(activity)) {
64 trySend(Unit)
65 }
66 wasInMultiWindowMode = activity.isInMultiWindowMode
67 wasInPictureInPictureMode = activity.isInPictureInPictureMode
68 }
69 }
70
71 /**
72 * Whenever application is launched in PiP or multi-window mode, onPaused() lifecycle
73 * callback is triggered.
74 */
75 override fun onActivityPaused(activity: Activity) {
76 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
77 wasInMultiWindowMode = activity.isInMultiWindowMode
78 wasInPictureInPictureMode = activity.isInPictureInPictureMode
79 }
80 }
81
82 override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
83 override fun onActivityDestroyed(activity: Activity) {}
84
85 /**
86 * Returns whether [activity] was previously in multi-window mode or PiP mode.
87 */
88 @RequiresApi(Build.VERSION_CODES.N)
89 private fun isActivityResumedAfterMultiWindowOrPiPMode(activity: Activity) =
90 (wasInMultiWindowMode == true && !activity.isInMultiWindowMode) ||
91 (wasInPictureInPictureMode == true && !activity.isInPictureInPictureMode)
92 }
93
94 registerActivityLifecycleCallbacks(callback)
95
96 awaitClose {
97 // Cleanup
98 unregisterActivityLifecycleCallbacks(callback)
99 }
100 }