Skip to content

Commit

Permalink
Request permission on Android 13
Browse files Browse the repository at this point in the history
  • Loading branch information
pyricau committed Nov 10, 2022
1 parent ae23910 commit 9e3d3ee
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 20 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Expand Up @@ -3,7 +3,7 @@ import org.jetbrains.dokka.gradle.DokkaTask
buildscript {
ext.versions = [
'minSdk' : 14,
'compileSdk': 31,
'compileSdk': 33,
]
repositories {
google()
Expand Down
7 changes: 4 additions & 3 deletions leakcanary-android-core/src/main/AndroidManifest.xml
Expand Up @@ -22,8 +22,9 @@
<!-- To store the heap dumps and leak analysis results. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- To allow starting foreground services on Android P+ - https://developer.android.com/preview/behavior-changes#fg-svc -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

<!-- To allow posting notifications on Android 13 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

<application>
<provider
Expand Down Expand Up @@ -92,7 +93,7 @@
</activity-alias>

<activity
android:name="leakcanary.internal.RequestStoragePermissionActivity"
android:name="leakcanary.internal.RequestPermissionActivity"
android:excludeFromRecents="true"
android:icon="@mipmap/leak_canary_icon"
android:label="@string/leak_canary_storage_permission_activity_label"
Expand Down
Expand Up @@ -111,12 +111,13 @@ internal class LeakDirectoryProvider constructor(
}

fun requestWritePermissionNotification() {
if (permissionNotificationDisplayed) {
if (permissionNotificationDisplayed || !Notifications.canShowNotification) {
return
}
permissionNotificationDisplayed = true

val pendingIntent = RequestStoragePermissionActivity.createPendingIntent(context)
val pendingIntent =
RequestPermissionActivity.createPendingIntent(context, WRITE_EXTERNAL_STORAGE)
val contentTitle = context.getString(
R.string.leak_canary_permission_notification_title
)
Expand Down
Expand Up @@ -15,6 +15,7 @@
*/
package leakcanary.internal

import android.Manifest.permission.POST_NOTIFICATIONS
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
Expand All @@ -26,17 +27,55 @@ import android.os.Build.VERSION_CODES.O
import com.squareup.leakcanary.core.R
import leakcanary.LeakCanary
import leakcanary.internal.InternalLeakCanary.FormFactor.MOBILE
import shark.SharkLog

internal object Notifications {

private var notificationPermissionRequested = false

// Instant apps cannot show background notifications
// See https://github.com/square/leakcanary/issues/1197
// TV devices can't show notifications.
// Watch devices: not sure, but probably not a good idea anyway?
val canShowNotification: Boolean
get() = InternalLeakCanary.formFactor == MOBILE &&
(!InternalLeakCanary.isInstantApp || InternalLeakCanary.applicationVisible) &&
LeakCanary.config.showNotifications
get() {
if (InternalLeakCanary.formFactor != MOBILE) {
return false
}
if (InternalLeakCanary.isInstantApp || !InternalLeakCanary.applicationVisible) {
return false
}
if (!LeakCanary.config.showNotifications) {
return false
}
if (SDK_INT >= 33) {
val application = InternalLeakCanary.application
if (application.applicationInfo.targetSdkVersion >= 33) {
val notificationManager =
application.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (!notificationManager.areNotificationsEnabled()) {
if (notificationPermissionRequested) {
SharkLog.d { "Not showing notification: already requested missing POST_NOTIFICATIONS permission." }
} else {
SharkLog.d { "Not showing notification: requesting missing POST_NOTIFICATIONS permission." }
application.startActivity(
RequestPermissionActivity.createIntent(
application,
POST_NOTIFICATIONS
)
)
notificationPermissionRequested = true
}
return false
}
if (notificationManager.areNotificationsPaused()) {
SharkLog.d { "Not showing notification, notifications are paused." }
return false
}
}
}
return true
}

@Suppress("LongParameterList")
fun showNotification(
Expand Down
Expand Up @@ -15,7 +15,6 @@
*/
package leakcanary.internal

import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.annotation.TargetApi
import android.app.Activity
import android.app.PendingIntent
Expand All @@ -33,17 +32,20 @@ import android.widget.Toast.LENGTH_LONG
import com.squareup.leakcanary.core.R

@TargetApi(Build.VERSION_CODES.M) //
internal class RequestStoragePermissionActivity : Activity() {
internal class RequestPermissionActivity : Activity() {

private val targetPermission: String
get() = intent.getStringExtra(TARGET_PERMISSION_EXTRA)!!

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

if (savedInstanceState == null) {
if (hasStoragePermission()) {
if (hasTargetPermission()) {
finish()
return
}
val permissions = arrayOf(WRITE_EXTERNAL_STORAGE)
val permissions = arrayOf(targetPermission)
requestPermissions(permissions, 42)
}
}
Expand All @@ -53,7 +55,7 @@ internal class RequestStoragePermissionActivity : Activity() {
permissions: Array<String>,
grantResults: IntArray
) {
if (!hasStoragePermission()) {
if (!hasTargetPermission()) {
Toast.makeText(application, R.string.leak_canary_permission_not_granted, LENGTH_LONG)
.show()
}
Expand All @@ -66,15 +68,22 @@ internal class RequestStoragePermissionActivity : Activity() {
super.finish()
}

private fun hasStoragePermission(): Boolean {
return checkSelfPermission(WRITE_EXTERNAL_STORAGE) == PERMISSION_GRANTED
private fun hasTargetPermission(): Boolean {
return checkSelfPermission(targetPermission) == PERMISSION_GRANTED
}

companion object {
private const val TARGET_PERMISSION_EXTRA = "targetPermission"

fun createIntent(context: Context, permission: String): Intent {
return Intent(context, RequestPermissionActivity::class.java).apply {
flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TOP
putExtra(TARGET_PERMISSION_EXTRA, permission)
}
}

fun createPendingIntent(context: Context): PendingIntent {
val intent = Intent(context, RequestStoragePermissionActivity::class.java)
intent.flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TOP
fun createPendingIntent(context: Context, permission: String): PendingIntent {
val intent = createIntent(context, permission)
val flags = if (Build.VERSION.SDK_INT >= 23) {
FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
} else {
Expand Down
Expand Up @@ -63,7 +63,7 @@
<string name="leak_canary_delete">Delete</string>
<string name="leak_canary_delete_all">Delete all</string>
<string name="leak_canary_delete_all_leaks_title">Are you sure you want to delete all leaks?</string>
<string name="leak_canary_permission_not_granted">Please grant external storage permission, otherwise memory leaks will not be detected.</string>
<string name="leak_canary_permission_not_granted">Please grant requested permission, otherwise memory leak detection may not work.</string>
<string name="leak_canary_permission_notification_title">Leak detected, need permission</string>
<string name="leak_canary_permission_notification_text">Click to enable storage permission for %s.</string>
<string name="leak_canary_shortcut_label">Leaks</string>
Expand Down

0 comments on commit 9e3d3ee

Please sign in to comment.