Skip to content

Commit

Permalink
Reporting failures
Browse files Browse the repository at this point in the history
Fixes #102
  • Loading branch information
pyricau committed May 16, 2015
1 parent 3f8dfd7 commit 5be5ec2
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* `leakcanary-android-no-op` is lighter, it does not depend on `leakcanary-watcher` anymore, only 2 classes now: [#74](https://github.com/square/leakcanary/issues/74).
* Adding field state details to the text leak trace.
* A Toast is displayed while the heap dump is in progress to warn that the UI will freeze: [#20](https://github.com/square/leakcanary/issues/49). You can customize the toast by providing your own layout named `__leak_canary_heap_dump_toast.xml` (e.g. you could make it an empty layout).
* If the analysis fails, the result and heap dump are kept so that it can be reported to LeakCanary: [#102](https://github.com/square/leakcanary/issues/102).

### Public API changes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ protected final void onHeapAnalyzed(HeapDump heapDump, AnalysisResult result) {
}
}

if (!result.leakFound || result.excludedLeak) {
if (result.failure == null && (!result.leakFound || result.excludedLeak)) {
afterDefaultHandling(heapDump, result, leakInfo);
return;
}
Expand Down Expand Up @@ -97,8 +97,13 @@ protected final void onHeapAnalyzed(HeapDump heapDump, AnalysisResult result) {
PendingIntent pendingIntent =
DisplayLeakActivity.createPendingIntent(this, heapDump.referenceKey);

String contentTitle =
getString(R.string.__leak_canary_class_has_leaked, classSimpleName(result.className));
String contentTitle;
if (result.failure == null) {
contentTitle =
getString(R.string.__leak_canary_class_has_leaked, classSimpleName(result.className));
} else {
contentTitle = getString(R.string.__leak_canary_analysis_failed);
}
String contentText = getString(R.string.__leak_canary_notification_message);

NotificationManager notificationManager =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
import static android.text.format.DateUtils.FORMAT_SHOW_TIME;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static com.squareup.leakcanary.LeakCanary.leakInfo;
import static com.squareup.leakcanary.internal.LeakCanaryInternals.detectedLeakDirectory;
import static com.squareup.leakcanary.internal.LeakCanaryInternals.leakResultFile;
Expand All @@ -78,6 +80,7 @@ public static PendingIntent createPendingIntent(Context context, String referenc
private String visibleLeakRefKey;

private ListView listView;
private TextView failureView;
private Button actionButton;
private int maxStoredLeaks;

Expand All @@ -99,6 +102,7 @@ public static PendingIntent createPendingIntent(Context context, String referenc
setContentView(R.layout.__leak_canary_display_leak);

listView = (ListView) findViewById(R.id.__leak_canary_display_leak_list);
failureView = (TextView) findViewById(R.id.__leak_canary_display_leak_failure);
actionButton = (Button) findViewById(R.id.__leak_canary_action);

maxStoredLeaks = getResources().getInteger(R.integer.__leak_canary_max_stored_leaks);
Expand Down Expand Up @@ -198,40 +202,58 @@ private void updateUi() {
}

ListAdapter listAdapter = listView.getAdapter();
// Reset to defaults
listView.setVisibility(VISIBLE);
failureView.setVisibility(GONE);

if (visibleLeak != null) {
final DisplayLeakAdapter adapter;
if (listAdapter instanceof DisplayLeakAdapter) {
adapter = (DisplayLeakAdapter) listAdapter;
} else {
adapter = new DisplayLeakAdapter();
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
adapter.toggleRow(position);
}
});
AnalysisResult result = visibleLeak.result;
if (result.failure != null) {
listView.setVisibility(GONE);
failureView.setVisibility(VISIBLE);
failureView.setText(
getString(R.string.__leak_canary_failure_report) + Log.getStackTraceString(
result.failure));
setTitle(R.string.__leak_canary_analysis_failed);
invalidateOptionsMenu();
getActionBar().setDisplayHomeAsUpEnabled(true);
actionButton.setVisibility(View.VISIBLE);
actionButton.setText("Remove leak");
actionButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
Leak visibleLeak = getVisibleLeak();
File resultFile = leakResultFile(visibleLeak.heapDump.heapDumpFile);
resultFile.delete();
visibleLeak.heapDump.heapDumpFile.delete();
visibleLeakRefKey = null;
leaks.remove(visibleLeak);
updateUi();
}
});
actionButton.setVisibility(VISIBLE);
actionButton.setText(R.string.__leak_canary_delete);
listView.setAdapter(null);
} else {
final DisplayLeakAdapter adapter;
if (listAdapter instanceof DisplayLeakAdapter) {
adapter = (DisplayLeakAdapter) listAdapter;
} else {
adapter = new DisplayLeakAdapter();
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
adapter.toggleRow(position);
}
});
invalidateOptionsMenu();
getActionBar().setDisplayHomeAsUpEnabled(true);
actionButton.setVisibility(VISIBLE);
actionButton.setText(R.string.__leak_canary_delete);
actionButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
Leak visibleLeak = getVisibleLeak();
File resultFile = leakResultFile(visibleLeak.heapDump.heapDumpFile);
resultFile.delete();
visibleLeak.heapDump.heapDumpFile.delete();
visibleLeakRefKey = null;
leaks.remove(visibleLeak);
updateUi();
}
});
}
HeapDump heapDump = visibleLeak.heapDump;
adapter.update(result.leakTrace, heapDump.referenceKey, heapDump.referenceName);
setTitle(
getString(R.string.__leak_canary_class_has_leaked, classSimpleName(result.className)));
}
AnalysisResult result = visibleLeak.result;
HeapDump heapDump = visibleLeak.heapDump;
adapter.update(result.leakTrace, heapDump.referenceKey, heapDump.referenceName);
setTitle(
getString(R.string.__leak_canary_class_has_leaked, classSimpleName(result.className)));
} else {
if (listAdapter instanceof LeakListAdapter) {
((LeakListAdapter) listAdapter).notifyDataSetChanged();
Expand All @@ -248,7 +270,7 @@ public void onItemClick(AdapterView<?> parent, View view, int position, long id)
invalidateOptionsMenu();
setTitle(getString(R.string.__leak_canary_leak_list_title, getPackageName()));
getActionBar().setDisplayHomeAsUpEnabled(false);
actionButton.setText("Remove all leaks");
actionButton.setText(R.string.__leak_canary_delete_all);
actionButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
File[] files = detectedLeakDirectory().listFiles();
Expand All @@ -262,7 +284,7 @@ public void onItemClick(AdapterView<?> parent, View view, int position, long id)
}
});
}
actionButton.setVisibility(leaks.size() == 0 ? View.GONE : View.VISIBLE);
actionButton.setVisibility(leaks.size() == 0 ? GONE : VISIBLE);
}
}

Expand Down Expand Up @@ -308,8 +330,16 @@ class LeakListAdapter extends BaseAdapter {
index = (leaks.size() - position) + ". ";
}

String title = index + getString(R.string.__leak_canary_class_has_leaked,
classSimpleName(leak.result.className));
String title;
if (leak.result.failure == null) {
title = index + getString(R.string.__leak_canary_class_has_leaked,
classSimpleName(leak.result.className));
} else {
title = index
+ leak.result.failure.getClass().getSimpleName()
+ " "
+ leak.result.failure.getMessage();
}
titleView.setText(title);
String time = DateUtils.formatDateTime(DisplayLeakActivity.this,
leak.heapDump.heapDumpFile.lastModified(), FORMAT_SHOW_TIME | FORMAT_SHOW_DATE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@
android:dividerHeight="0dp"
android:divider="@null"
/>

<TextView
android:id="@+id/__leak_canary_display_leak_failure"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:textSize="12sp"
android:visibility="gone"
/>
<Button
android:id="@+id/__leak_canary_action"
android:layout_width="match_parent"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@
<resources>

<string name="__leak_canary_class_has_leaked">%s has leaked</string>
<string name="__leak_canary_analysis_failed">Leak analysis failed</string>
<string name="__leak_canary_leak_list_title">Leaks in %s</string>
<string name="__leak_canary_notification_message">Click for more details</string>
<string name="__leak_canary_share_leak">Share leak</string>
<string name="__leak_canary_share_leak">Share info</string>
<string name="__leak_canary_share_heap_dump">Share heap dump</string>
<string name="__leak_canary_share_with">Share with…</string>
<string name="__leak_canary_display_activity_label">Leaks</string>
<string name="__leak_canary_toast_heap_dump">Dumping memory, app will freeze. Brrrr.</string>
<string name="__leak_canary_delete">Delete</string>
<string name="__leak_canary_failure_report">"Please report this failure to http://github.com/square/leakcanary\n"</string>
<string name="__leak_canary_delete_all">Delete all</string>

</resources>

0 comments on commit 5be5ec2

Please sign in to comment.