From 131a8ae309b8f422d54685875ee0568da50ef2dc Mon Sep 17 00:00:00 2001 From: Pierre-Yves Ricau Date: Fri, 22 Jan 2016 17:13:25 -0800 Subject: [PATCH] Fix permission crash for DisplayLeakActivity on M Fixes #382 --- .../leakcanary/AndroidHeapDumper.java | 2 +- .../DefaultLeakDirectoryProvider.java | 13 ++++++++- .../leakcanary/LeakDirectoryProvider.java | 5 +++- .../internal/DisplayLeakActivity.java | 27 +++++++++++-------- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidHeapDumper.java b/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidHeapDumper.java index 86a232f0a5..c46435f35b 100644 --- a/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidHeapDumper.java +++ b/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidHeapDumper.java @@ -47,7 +47,7 @@ public AndroidHeapDumper(Context context, LeakDirectoryProvider leakDirectoryPro @Override public File dumpHeap() { if (!leakDirectoryProvider.isLeakStorageWritable()) { CanaryLog.d("Could not write to leak storage to dump heap."); - leakDirectoryProvider.requestWritePermission(); + leakDirectoryProvider.requestWritePermissionNotification(); return NO_DUMP; } File heapDumpFile = getHeapDumpFile(); diff --git a/leakcanary-android/src/main/java/com/squareup/leakcanary/DefaultLeakDirectoryProvider.java b/leakcanary-android/src/main/java/com/squareup/leakcanary/DefaultLeakDirectoryProvider.java index 988906e31e..812b6e6478 100644 --- a/leakcanary-android/src/main/java/com/squareup/leakcanary/DefaultLeakDirectoryProvider.java +++ b/leakcanary-android/src/main/java/com/squareup/leakcanary/DefaultLeakDirectoryProvider.java @@ -16,6 +16,7 @@ package com.squareup.leakcanary; import android.annotation.TargetApi; +import android.app.Activity; import android.app.PendingIntent; import android.content.Context; import android.os.Environment; @@ -48,7 +49,7 @@ public DefaultLeakDirectoryProvider(Context context) { return directory; } - @Override public void requestWritePermission() { + @Override public void requestWritePermissionNotification() { if (hasStoragePermission()) { return; } @@ -60,6 +61,16 @@ public DefaultLeakDirectoryProvider(Context context) { showNotification(context, contentTitle, contentText, pendingIntent); } + @TargetApi(M) @Override public void requestPermission(Activity activity) { + if (hasStoragePermission()) { + return; + } + String[] permissions = { + WRITE_EXTERNAL_STORAGE + }; + activity.requestPermissions(permissions, 42); + } + @Override public boolean isLeakStorageWritable() { if (!hasStoragePermission()) { return false; diff --git a/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakDirectoryProvider.java b/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakDirectoryProvider.java index 6c8cf05688..1e7ebf87bd 100644 --- a/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakDirectoryProvider.java +++ b/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakDirectoryProvider.java @@ -15,6 +15,7 @@ */ package com.squareup.leakcanary; +import android.app.Activity; import java.io.File; /** @@ -27,7 +28,9 @@ public interface LeakDirectoryProvider { /** Returns a path to an existing directory were leaks can be stored. */ File leakDirectory(); - void requestWritePermission(); + void requestWritePermissionNotification(); + + void requestPermission(Activity activity); /** True if we can currently write to the leak directory. */ boolean isLeakStorageWritable(); diff --git a/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/DisplayLeakActivity.java b/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/DisplayLeakActivity.java index 2be0290d36..e746b04c54 100644 --- a/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/DisplayLeakActivity.java +++ b/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/DisplayLeakActivity.java @@ -88,13 +88,12 @@ public static void setLeakDirectoryProvider(LeakDirectoryProvider leakDirectoryP DisplayLeakActivity.leakDirectoryProvider = leakDirectoryProvider; } - static File getLeakDirectory(Context context) { + private static LeakDirectoryProvider leakDirectoryProvider(Context context) { LeakDirectoryProvider leakDirectoryProvider = DisplayLeakActivity.leakDirectoryProvider; - if (leakDirectoryProvider != null) { - return leakDirectoryProvider.leakDirectory(); - } else { - return new DefaultLeakDirectoryProvider(context).leakDirectory(); + if (leakDirectoryProvider == null) { + leakDirectoryProvider = new DefaultLeakDirectoryProvider(context); } + return leakDirectoryProvider; } // null until it's been first loaded. @@ -141,7 +140,13 @@ static File getLeakDirectory(Context context) { @Override protected void onResume() { super.onResume(); - LoadLeaks.load(this); + LeakDirectoryProvider leakDirectoryProvider = leakDirectoryProvider(this); + if (leakDirectoryProvider.isLeakStorageWritable()) { + File leakDirectory = leakDirectoryProvider.leakDirectory(); + LoadLeaks.load(this, leakDirectory); + } else { + leakDirectoryProvider.requestPermission(this); + } } @Override public void setTheme(int resid) { @@ -237,7 +242,7 @@ void deleteVisibleLeak() { } void deleteAllLeaks() { - File leakDirectory = getLeakDirectory(DisplayLeakActivity.this); + File leakDirectory = leakDirectoryProvider(DisplayLeakActivity.this).leakDirectory(); File[] files = leakDirectory.listFiles(); if (files != null) { for (File file : files) { @@ -428,8 +433,8 @@ static class LoadLeaks implements Runnable { static final Executor backgroundExecutor = newSingleThreadExecutor("LoadLeaks"); - static void load(DisplayLeakActivity activity) { - LoadLeaks loadLeaks = new LoadLeaks(activity); + static void load(DisplayLeakActivity activity, File leakDirectory) { + LoadLeaks loadLeaks = new LoadLeaks(activity, leakDirectory); inFlight.add(loadLeaks); backgroundExecutor.execute(loadLeaks); } @@ -445,9 +450,9 @@ static void forgetActivity() { private final File leakDirectory; private final Handler mainHandler; - LoadLeaks(DisplayLeakActivity activity) { + LoadLeaks(DisplayLeakActivity activity, File leakDirectory) { this.activityOrNull = activity; - leakDirectory = getLeakDirectory(activity); + this.leakDirectory = leakDirectory; mainHandler = new Handler(Looper.getMainLooper()); }