• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package leakcanary.internal.activity
2 
3 import android.annotation.SuppressLint
4 import android.content.ActivityNotFoundException
5 import android.content.ClipData
6 import android.content.ClipboardManager
7 import android.content.Context
8 import android.content.Intent
9 import android.net.Uri
10 import android.os.AsyncTask
11 import android.os.Build
12 import android.view.View
13 import android.widget.Toast
14 import com.squareup.leakcanary.core.BuildConfig
15 import com.squareup.leakcanary.core.R
16 import leakcanary.internal.LeakCanaryFileProvider
17 import leakcanary.internal.navigation.activity
18 import shark.HeapAnalysisFailure
19 import java.io.File
20 
sharenull21 internal fun View.share(content: String) {
22   val intent = Intent(Intent.ACTION_SEND)
23   intent.type = "text/plain"
24   intent.putExtra(Intent.EXTRA_TEXT, content)
25   activity.startActivity(
26     Intent.createChooser(intent, resources.getString(R.string.leak_canary_share_with))
27   )
28 }
29 
30 @SuppressLint("SetWorldReadable")
shareHeapDumpnull31 internal fun View.shareHeapDump(heapDumpFile: File) {
32   AsyncTask.SERIAL_EXECUTOR.execute {
33     heapDumpFile.setReadable(true, false)
34     val heapDumpUri = LeakCanaryFileProvider.getUriForFile(
35       activity,
36       "com.squareup.leakcanary.fileprovider." + activity.packageName,
37       heapDumpFile
38     )
39     activity.runOnUiThread { startShareIntentChooser(heapDumpUri) }
40   }
41 }
42 
startShareIntentChoosernull43 private fun View.startShareIntentChooser(uri: Uri) {
44   val intent = Intent(Intent.ACTION_SEND)
45   intent.type = "application/octet-stream"
46   intent.putExtra(Intent.EXTRA_STREAM, uri)
47   activity.startActivity(
48     Intent.createChooser(intent, resources.getString(R.string.leak_canary_share_with))
49   )
50 }
51 
shareToStackOverflownull52 internal fun View.shareToStackOverflow(content: String) {
53   val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
54   // AsyncTask was needed here due to setPrimaryClip making a disk write which
55   // violated StrictMode if on the main thread
56   AsyncTask.execute {
57     clipboard.setPrimaryClip(
58       ClipData.newPlainText(
59         context.getString(R.string.leak_canary_leak_clipdata_label),
60         "```\n$content```"
61       )
62     )
63   }
64   Toast.makeText(context, R.string.leak_canary_leak_copied, Toast.LENGTH_LONG)
65     .show()
66   val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(STACKOVERFLOW_QUESTION_URL))
67   try {
68     activity.startActivity(browserIntent)
69   } catch (e: ActivityNotFoundException) {
70     Toast.makeText(context, R.string.leak_canary_leak_missing_browser_error, Toast.LENGTH_LONG)
71       .show()
72   }
73 }
74 
shareToGitHubIssuenull75 internal fun View.shareToGitHubIssue(failure: HeapAnalysisFailure) {
76   val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
77   // AsyncTask was needed here due to setPrimaryClip making a disk write which
78   // violated StrictMode if on the main thread
79   AsyncTask.execute {
80     clipboard.setPrimaryClip(
81       ClipData.newPlainText(
82         context.getString(R.string.leak_canary_failure_clipdata_label),
83         """```
84           |${failure.exception}
85           |Build.VERSION.SDK_INT: ${Build.VERSION.SDK_INT}
86           |Build.MANUFACTURER: ${Build.MANUFACTURER}
87           |LeakCanary version: ${BuildConfig.LIBRARY_VERSION}
88           |Analysis duration: ${failure.analysisDurationMillis} ms
89           |Heap dump file path: ${failure.heapDumpFile.absolutePath}
90           |Heap dump timestamp: ${failure.createdAtTimeMillis}
91           |```
92         """.trimMargin()
93       )
94     )
95   }
96   Toast.makeText(context, R.string.leak_canary_failure_copied, Toast.LENGTH_LONG)
97     .show()
98   val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(NEW_ISSUE_URL))
99   try {
100     activity.startActivity(browserIntent)
101   } catch (e: ActivityNotFoundException) {
102     Toast.makeText(context, R.string.leak_canary_leak_missing_browser_error, Toast.LENGTH_LONG)
103       .show()
104   }
105 }
106 
107 private const val STACKOVERFLOW_QUESTION_URL =
108   "http://stackoverflow.com/questions/ask?guided=false&tags=leakcanary"
109 
110 private const val NEW_ISSUE_URL =
111   "https://github.com/square/leakcanary/issues/new?labels=type%3A+bug&template=2-bug.md"
112