Skip to content

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 Maps & Navigation SDK for Android archive file

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

Send debug info android example screenshot

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

Android example screenshot
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.

Android Examples

Maps SDK for Android Examples can be downloaded or cloned with Git