<lambda>null1 package leakcanary.internal.activity.screen
2
3 import android.app.ActivityManager
4 import android.app.AlertDialog
5 import android.view.View
6 import android.view.ViewGroup
7 import android.widget.ListView
8 import android.widget.TextView
9 import com.squareup.leakcanary.core.R
10 import leakcanary.LeakCanary
11 import leakcanary.internal.activity.LeakActivity
12 import leakcanary.internal.activity.db.HeapAnalysisTable
13 import leakcanary.internal.activity.db.HeapAnalysisTable.Projection
14 import leakcanary.internal.activity.db.executeOnDb
15 import leakcanary.internal.activity.ui.SimpleListAdapter
16 import leakcanary.internal.activity.ui.TimeFormatter
17 import leakcanary.internal.navigation.NavigatingActivity
18 import leakcanary.internal.navigation.Screen
19 import leakcanary.internal.navigation.activity
20 import leakcanary.internal.navigation.goTo
21 import leakcanary.internal.navigation.inflate
22 import leakcanary.internal.navigation.onCreateOptionsMenu
23 import leakcanary.internal.navigation.onScreenExiting
24
25 internal class HeapDumpsScreen : Screen() {
26 override fun createView(container: ViewGroup) =
27 container.inflate(R.layout.leak_canary_heap_dumps_screen).apply {
28
29 val unsubscribeRefresh = HeapAnalysisTable.onUpdate {
30 activity<NavigatingActivity>().refreshCurrentScreen()
31 }
32
33 onScreenExiting { unsubscribeRefresh() }
34
35 onCreateOptionsMenu { menu ->
36 if (!ActivityManager.isUserAMonkey()) {
37 menu.add(R.string.leak_canary_delete_all)
38 .setOnMenuItemClickListener {
39 AlertDialog.Builder(context)
40 .setIcon(android.R.drawable.ic_dialog_alert)
41 .setTitle(R.string.leak_canary_delete_all)
42 .setMessage(R.string.leak_canary_delete_all_leaks_title)
43 .setPositiveButton(android.R.string.ok) { _, _ ->
44 executeOnDb {
45 HeapAnalysisTable.deleteAll(db)
46 updateUi {
47 val listView = findViewById<ListView>(R.id.leak_canary_list)
48 listView.adapter =
49 SimpleListAdapter(
50 R.layout.leak_canary_simple_row, emptyList<Any>()
51 ) { _, _ -> }
52 }
53 }
54 }
55 .setNegativeButton(android.R.string.cancel, null)
56 .show()
57 true
58 }
59 }
60 }
61
62 findViewById<View>(R.id.leak_canary_import_heap_dump).setOnClickListener {
63 activity<LeakActivity>().requestImportHprof()
64 }
65
66 findViewById<View>(R.id.leak_canary_dump_heap_now).setOnClickListener {
67 LeakCanary.dumpHeap()
68 }
69
70 executeOnDb {
71 val projections = HeapAnalysisTable.retrieveAll(db)
72 updateUi { onAnalysesRetrieved(projections) }
73 }
74
75 }
76
77 private fun View.onAnalysesRetrieved(projections: List<Projection>) {
78 activity.title = resources.getQuantityString(
79 R.plurals.leak_canary_heap_analysis_list_screen_title,
80 projections.size, projections.size
81 )
82
83 val listView = findViewById<ListView>(R.id.leak_canary_list)
84
85 listView.setOnItemClickListener { _, _, position, _ ->
86 val projection = projections[position]
87 val analysisScreen = if (projection.exceptionSummary != null) {
88 HeapAnalysisFailureScreen(projection.id)
89 } else {
90 HeapDumpScreen(projection.id)
91 }
92 goTo(analysisScreen)
93 }
94
95 listView.adapter =
96 SimpleListAdapter(R.layout.leak_canary_leak_row, projections) { view, position ->
97 val goneView = view.findViewById<TextView>(R.id.leak_canary_count_text)
98 goneView.visibility = View.GONE
99 val timeView = view.findViewById<TextView>(R.id.leak_canary_leak_text)
100 val countView = view.findViewById<TextView>(R.id.leak_canary_time_text)
101
102 val projection = getItem(position)
103 // Enable means "new"
104 countView.isEnabled = false
105
106 timeView.text = TimeFormatter.formatTimestamp(view.context, projection.createdAtTimeMillis)
107
108 val count = projection.exceptionSummary ?: resources.getQuantityString(
109 R.plurals.leak_canary_distinct_leaks,
110 projection.leakCount, projection.leakCount
111 )
112 countView.text = count
113 }
114 }
115 }
116