@@ -15,7 +15,6 @@ import android.util.Log
15
15
import androidx.activity.result.ActivityResultCaller
16
16
import androidx.activity.result.ActivityResultLauncher
17
17
import androidx.activity.result.contract.ActivityResultContracts
18
- import androidx.appcompat.app.AppCompatActivity
19
18
import androidx.core.app.NotificationCompat
20
19
import androidx.core.app.NotificationManagerCompat
21
20
import androidx.core.content.ContextCompat
@@ -24,7 +23,6 @@ import com.google.firebase.ktx.Firebase
24
23
import com.googletest.firebase.appdistribution.testapp.NotificationFeedbackTrigger.SCREENSHOT_FILE_NAME
25
24
import com.googletest.firebase.appdistribution.testapp.NotificationFeedbackTrigger.takeScreenshot
26
25
import java.io.IOException
27
- import java.util.*
28
26
29
27
@SuppressLint(" StaticFieldLeak" ) // Reference to Activity is set to null in onActivityDestroyed
30
28
object NotificationFeedbackTrigger : Application.ActivityLifecycleCallbacks {
@@ -36,9 +34,6 @@ object NotificationFeedbackTrigger : Application.ActivityLifecycleCallbacks {
36
34
private var isEnabled = false
37
35
private var hasRequestedPermission = false
38
36
private var currentActivity: Activity ? = null
39
- // TODO(lkellogg): this is getting too complex - simplify it by, for example, only enabling this
40
- // trigger on a per-activity basis instead of app-wide
41
- private var requestPermissionLaunchers: WeakHashMap <Activity , ActivityResultLauncher <String >? > = WeakHashMap ()
42
37
43
38
fun initialize (application : Application ) {
44
39
// Create the NotificationChannel, but only on API 26+ because
@@ -59,11 +54,43 @@ object NotificationFeedbackTrigger : Application.ActivityLifecycleCallbacks {
59
54
application.registerActivityLifecycleCallbacks(this )
60
55
}
61
56
62
- fun enable (currentActivity : Activity ? = null) {
63
- this .currentActivity = currentActivity
57
+ fun <T > registerPermissionLauncher (activity : T ): ActivityResultLauncher <String >? where
58
+ T : Activity ,
59
+ T : ActivityResultCaller {
60
+ if (hasRequestedPermission) {
61
+ Log .i(TAG , " Already request permission; Not trying again." )
62
+ return null
63
+ }
64
+
65
+ return activity.registerForActivityResult(ActivityResultContracts .RequestPermission ()) {
66
+ isGranted: Boolean ->
67
+ if (! isEnabled) {
68
+ Log .w(TAG , " Trigger disabled after permission check. Abandoning notification." )
69
+ } else if (isGranted) {
70
+ showNotification(activity)
71
+ } else {
72
+ Log .i(TAG , " Permission not granted" )
73
+ // TODO: Ideally we would show a message indicating the impact of not
74
+ // enabling the permission, but there's no way to know if they've
75
+ // permanently denied the permission, and we don't want to show them a
76
+ // message after each time we try to post a notification.
77
+ }
78
+ }
79
+ }
80
+
81
+ fun enable (activity : Activity ? = null, launcher : ActivityResultLauncher <String >? = null) {
82
+ currentActivity = activity
64
83
isEnabled = true
65
- if (currentActivity != null ) {
66
- showNotification(currentActivity)
84
+ if (activity != null ) {
85
+ if (hasPermission(activity)) {
86
+ showNotification(activity)
87
+ } else {
88
+ if (launcher != null ) {
89
+ requestPermission(activity, launcher)
90
+ } else {
91
+ Log .i(TAG , " Not requesting permission, because of no launcher was provided." )
92
+ }
93
+ }
67
94
}
68
95
}
69
96
@@ -77,62 +104,52 @@ object NotificationFeedbackTrigger : Application.ActivityLifecycleCallbacks {
77
104
}
78
105
79
106
private fun showNotification (activity : Activity ) {
80
- if (ContextCompat .checkSelfPermission(activity, POST_NOTIFICATIONS ) == PERMISSION_GRANTED ) {
81
- val intent = Intent (activity, TakeScreenshotAndTriggerFeedbackActivity ::class .java)
82
- intent.addFlags(Intent .FLAG_ACTIVITY_NO_HISTORY )
83
- val pendingIntent =
84
- PendingIntent .getActivity(
85
- activity,
86
- /* requestCode= */ 0 ,
87
- intent,
88
- PendingIntent .FLAG_IMMUTABLE
89
- )
90
- val builder =
91
- NotificationCompat .Builder (activity, FEEBACK_NOTIFICATION_CHANNEL_ID )
92
- .setSmallIcon(R .mipmap.ic_launcher)
93
- .setContentTitle(activity.getText(R .string.feedback_notification_title))
94
- .setContentText(activity.getText(R .string.feedback_notification_text))
95
- .setPriority(NotificationCompat .PRIORITY_LOW )
96
- .setContentIntent(pendingIntent)
97
- val notificationManager = NotificationManagerCompat .from(activity)
98
- Log .i(TAG , " Showing notification" )
99
- notificationManager.notify(FEEDBACK_NOTIFICATION_ID , builder.build())
100
- } else {
101
- // no permission to post notifications - try to get it
102
- if (hasRequestedPermission) {
103
- Log .i(
104
- TAG ,
105
- " We've already request permission. Not requesting again for the life of the activity."
106
- )
107
- } else {
108
- requestPermission(activity)
109
- }
110
- }
107
+ val intent = Intent (activity, TakeScreenshotAndTriggerFeedbackActivity ::class .java)
108
+ intent.addFlags(Intent .FLAG_ACTIVITY_NO_HISTORY )
109
+ val pendingIntent =
110
+ PendingIntent .getActivity(
111
+ activity,
112
+ /* requestCode = */ 0 ,
113
+ intent,
114
+ PendingIntent .FLAG_IMMUTABLE
115
+ )
116
+ val builder =
117
+ NotificationCompat .Builder (activity, FEEBACK_NOTIFICATION_CHANNEL_ID )
118
+ .setSmallIcon(R .mipmap.ic_launcher)
119
+ .setContentTitle(activity.getText(R .string.feedback_notification_title))
120
+ .setContentText(activity.getText(R .string.feedback_notification_text))
121
+ .setPriority(NotificationCompat .PRIORITY_LOW )
122
+ .setContentIntent(pendingIntent)
123
+ val notificationManager = NotificationManagerCompat .from(activity)
124
+ Log .i(TAG , " Showing notification" )
125
+ notificationManager.notify(FEEDBACK_NOTIFICATION_ID , builder.build())
111
126
}
112
127
113
- private fun requestPermission (activity : Activity ) {
114
- var launcher = requestPermissionLaunchers[activity]
115
- if (launcher == null ) {
116
- Log .i(TAG , " Not requesting permission, because of inability to register for result." )
128
+ private fun hasPermission (activity : Activity ) =
129
+ ContextCompat .checkSelfPermission(activity, POST_NOTIFICATIONS ) == PERMISSION_GRANTED
130
+
131
+ private fun requestPermission (activity : Activity , launcher : ActivityResultLauncher <String >) {
132
+ if (hasRequestedPermission) {
133
+ Log .i(TAG , " Already request permission; Not trying again." )
134
+ return
135
+ }
136
+ if (activity.shouldShowRequestPermissionRationale(POST_NOTIFICATIONS )) {
137
+ Log .i(TAG , " Showing customer rationale for requesting permission." )
138
+ AlertDialog .Builder (activity)
139
+ .setMessage(
140
+ " Using a notification to initiate feedback to the developer. " +
141
+ " To enable this feature, allow the app to post notifications."
142
+ )
143
+ .setPositiveButton(" OK" ) { _, _ ->
144
+ Log .i(TAG , " Launching request for permission." )
145
+ launcher.launch(POST_NOTIFICATIONS )
146
+ }
147
+ .show()
117
148
} else {
118
- if (activity.shouldShowRequestPermissionRationale(POST_NOTIFICATIONS )) {
119
- Log .i(TAG , " Showing customer rationale for requesting permission." )
120
- AlertDialog .Builder (activity)
121
- .setMessage(
122
- " Using a notification to initiate feedback to the developer. " +
123
- " To enable this feature, allow the app to post notifications."
124
- )
125
- .setPositiveButton(" OK" ) { _, _ ->
126
- Log .i(TAG , " Launching request for permission." )
127
- launcher.launch(POST_NOTIFICATIONS )
128
- }
129
- .show()
130
- } else {
131
- Log .i(TAG , " Launching request for permission without rationale." )
132
- launcher.launch(POST_NOTIFICATIONS )
133
- }
134
- hasRequestedPermission = true
149
+ Log .i(TAG , " Launching request for permission without rationale." )
150
+ launcher.launch(POST_NOTIFICATIONS )
135
151
}
152
+ hasRequestedPermission = true
136
153
}
137
154
138
155
private fun cancelNotification (context : Context ) {
@@ -160,35 +177,10 @@ object NotificationFeedbackTrigger : Application.ActivityLifecycleCallbacks {
160
177
Log .d(TAG , " clearing current activity" )
161
178
currentActivity = null
162
179
}
163
- requestPermissionLaunchers[activity] = null
164
- }
165
-
166
- override fun onActivityCreated (activity : Activity , savedInstanceState : Bundle ? ) {
167
- if (activity is ActivityResultCaller && ! hasRequestedPermission) {
168
- requestPermissionLaunchers[activity] =
169
- activity.registerForActivityResult(ActivityResultContracts .RequestPermission ()) {
170
- isGranted: Boolean ->
171
- if (! isEnabled) {
172
- Log .w(TAG , " Trigger disabled after permission check. Abandoning notification." )
173
- } else if (isGranted) {
174
- showNotification(activity)
175
- } else {
176
- Log .i(TAG , " Permission not granted" )
177
- // TODO: Ideally we would show a message indicating the impact of not
178
- // enabling the permission, but there's no way to know if they've
179
- // permanently denied the permission, and we don't want to show them a
180
- // message after each time we try to post a notification.
181
- }
182
- }
183
- } else {
184
- Log .w(
185
- TAG ,
186
- " Not showing notification because this activity can't register for permission request results: $activity "
187
- )
188
- }
189
180
}
190
181
191
182
// Other lifecycle methods
183
+ override fun onActivityCreated (activity : Activity , savedInstanceState : Bundle ? ) {}
192
184
override fun onActivityStarted (activity : Activity ) {}
193
185
override fun onActivityStopped (activity : Activity ) {}
194
186
override fun onActivitySaveInstanceState (activity : Activity , outState : Bundle ) {}
@@ -215,10 +207,10 @@ object NotificationFeedbackTrigger : Application.ActivityLifecycleCallbacks {
215
207
}
216
208
}
217
209
218
- class TakeScreenshotAndTriggerFeedbackActivity : AppCompatActivity () {
210
+ class TakeScreenshotAndTriggerFeedbackActivity : Activity () {
219
211
override fun onCreate (savedInstanceState : Bundle ? ) {
220
212
super .onCreate(savedInstanceState)
221
- takeScreenshot()
213
+ takeScreenshot() // at this point currentActivity still points to the previous activity
222
214
}
223
215
224
216
override fun onResume () {
0 commit comments