Send Debug Info¶
In this guide you will learn how to send
debug info from within an app. A button
to send the debug info is displayed on top of
an interactive map. When the user taps the
button, debug info such as the SDK version
is assembled and sent.
Setup¶
First, get an API key token, see the
Getting Started guide.
Download the SendDebugInfo project
archive file or clone the project with Git
See the Configure Android Example guide.
Run the example¶
In Android Studio, from the File
menu, select Sync Project with Gradle Files
An android device should be connected via USB cable.
Press SHIFT+F10 to compile, install and run the example on the
android device.
How it works¶
You can open the MainActivity.kt file to see how to send
debug info from within an app. In this example, a button
to send the debug info is displayed on top of an interactive map.
1override fun onCreate(savedInstanceState: Bundle?)
2{
3 super.onCreate(savedInstanceState)
4 setContentView(R.layout.activity_main)
5 progressBar = findViewById(R.id.progressBar)
6 gemSurfaceView = findViewById(R.id.gem_surface)
7 sendDebugInfoButton = findViewById(R.id.sendDebugInfo)
8 progressBar.visibility = View.VISIBLE
9 sendDebugInfoButton.setOnClickListener {
10 var subject = ""
11 SdkCall.execute {
12 subject = GemSdk.sdkVersion?.let {
13 String.format("User feedback (SDK example) - %d.%d.%d.%d.%s", it.major, it.minor, it.year, it.week, it.revision)
14 } ?: "User feedback"
15 System.gc()
16 }
17 GEMLog.debug(this, "This is an UI message!")
18 sendFeedback(this, "support@magicearth.com", subject)
19 }
20 SdkSettings.onMapDataReady = {
21 Util.postOnMain {
22 progressBar.visibility = View.GONE
23 sendDebugInfoButton.visibility = View.VISIBLE
24 }
25 }
26 SdkSettings.onApiTokenRejected = {
27 showDialog("TOKEN REJECTED")
28 }
29 if (!Util.isInternetConnected(this))
30 {
31 showDialog("You must be connected to the internet!")
32 }
33}
The
onCreate()
function is overridden in the
MainActivity: AppCompatActivity()
class, and checks if
internet access is available, showing a dialog message if not.findViewById()
is used to obtain pointers to the various
graphical user interface elements where text or graphical data
is to be displayed.A click listener is set for the button to send the debug info:
sendDebugInfoButton.setOnClickListener {
A string containing the SDK version, date, and revision is
created when the button is clicked by the user.
The debug string is sent like this:
sendFeedback(this, "support@magicearth.com", subject)
When the map is loaded,
SdkSettings.onMapDataReady = {
the button is made visible so the user can click on it
to send the debug data:
sendDebugInfoButton.visibility = View.VISIBLE
1private fun sendFeedback(a: Activity, email: String, subject: String)
2{
3 val sendFeedbackTask = SendFeedbackTask(a, email, subject)
4 sendFeedbackTask.execute(null)
5}
The
sendFeedback()
function executes the sendFeedbackTask
. 1private class SendFeedbackTask(val activity: Activity, val email: String, val subject: String)
2: CoroutinesAsyncTask<Void, Void, Intent>()
3{
4 override fun doInBackground(vararg params: Void?): Intent
5 {
6 val subjectText = subject
7 val sendIntent = Intent(Intent.ACTION_SEND_MULTIPLE)
8 sendIntent.type = "message/rfc822"
9 sendIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf(email))
10 sendIntent.putExtra(Intent.EXTRA_SUBJECT, subjectText)
11 val emailBody = "\n\n$subjectText"
12 sendIntent.putExtra(Intent.EXTRA_TEXT, emailBody)
13 var publicLogPath = ""
14 val privateLogPath = GemSdk.appLogPath
15 privateLogPath?.let {
16 val path = GemUtil.getApplicationPublicFilesAbsolutePath(activity, "phoneLog.txt")
17 if (GemUtil.copyFile(it, path))
18 {
19 publicLogPath = path
20 }
21 }
22 val uris = ArrayList<Uri>()
23 if (publicLogPath.isNotEmpty())
24 {
25 val file = File(publicLogPath)
26 file.deleteOnExit()
27 try
28 {
29 uris.add(FileProvider.getUriForFile(activity, activity.packageName + ".provider", file))
30 }
31 catch (e: Exception)
32 {
33 GEMLog.error(this, "SendFeedbackTask.doInBackground(): error = ${e.message}")
34 }
35 }
36 if (GemSdk.internalStoragePath.isNotEmpty())
37 {
38 val gmCrashesPath = GemSdk.internalStoragePath + File.separator + "GMcrashlogs" + File.separator + "last"
39 val file = File(gmCrashesPath)
40 if (file.exists() && file.isDirectory)
41 {
42 val files = file.listFiles()
43 files?.forEach breakLoop@{
44 try
45 {
46 uris.add(FileProvider.getUriForFile(activity, activity.packageName + ".provider", it))
47 }
48 catch (e: Exception)
49 {
50 GEMLog.error(this, "SendFeedbackTask.doInBackground(): error = ${e.message}")
51 }
52 return@breakLoop
53 }
54 }
55 }
56 sendIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
57 return sendIntent
58 }
59 override fun onPostExecute(result: Intent?)
60 {
61 if (result == null)
62 {
63 return
64 }
65 activity.startActivity(result)
66 }
67}
The
sendFeedbackTask
class contains two overridden functions:override fun doInBackground()
This function assembles an email message containing the phone log and
all the files listed in the most recent crash log, and sends it.
override fun onPostExecute()
This function restarts the app after the debug message was sent.