Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions mobile/src/main/java/net/activitywatch/android/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import net.activitywatch.android.databinding.ActivityMainBinding
import net.activitywatch.android.fragments.TestFragment
import net.activitywatch.android.fragments.WebUIFragment
import net.activitywatch.android.watcher.UsageStatsWatcher
import java.net.URLEncoder
import java.nio.charset.StandardCharsets

private const val TAG = "MainActivity"

Expand All @@ -53,6 +55,31 @@ internal fun initialWebUiUrl(
internal fun shouldOpenActivityViewImmediately(openActivityView: Boolean, isResumed: Boolean): Boolean =
openActivityView && isResumed

internal const val BUG_REPORT_ISSUE_URL = "https://github.com/ActivityWatch/aw-android/issues/new"

/** Prefilled GitHub issue URL for the drawer "Report bugs" item. */
internal fun bugReportUrl(appVersion: String, androidVersion: String, apiLevel: Int): String {
val body = """
## Description

Describe the problem here.

## Steps to reproduce

1.

## Expected behavior

Describe what you expected to happen.

## Environment

- App version: $appVersion
- Android version: $androidVersion (API $apiLevel)
""".trimIndent()
return "$BUG_REPORT_ISSUE_URL?body=${URLEncoder.encode(body, StandardCharsets.UTF_8.name())}"
}

/** Native Home lives in MainActivity, so it inherits the last WebView chrome unless reset. */
internal fun shouldResetChromeForNativeDestination(isWebUiDestination: Boolean): Boolean =
!isWebUiDestination
Expand Down Expand Up @@ -104,6 +131,15 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
}
}

private fun openBugReport() {
val uri = Uri.parse(bugReportUrl(version, Build.VERSION.RELEASE, Build.VERSION.SDK_INT))
try {
startActivity(Intent(Intent.ACTION_VIEW, uri))
} catch (e: ActivityNotFoundException) {
Snackbar.make(binding.root, R.string.no_browser_found, Snackbar.LENGTH_SHORT).show()
}
}

override fun onFragmentInteraction(item: Uri) {
Log.w(TAG, "URI onInteraction listener not implemented")
}
Expand Down Expand Up @@ -336,8 +372,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
openDashboardInBrowser()
}
R.id.nav_send -> {
Snackbar.make(binding.coordinatorLayout, "The send button was clicked, but it's not yet implemented!", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
openBugReport()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import java.net.URLDecoder
import java.nio.charset.StandardCharsets

class MainActivityNavigationTest {
@Test
Expand Down Expand Up @@ -113,4 +115,35 @@ class MainActivityNavigationTest {
),
)
}

@Test
fun bugReportUrl_pointsAtNewIssueFormWithSingleBodyParam() {
val url = bugReportUrl(appVersion = "0.12.3", androidVersion = "14", apiLevel = 34)

assertTrue(url.startsWith("$BUG_REPORT_ISSUE_URL?body="))
assertFalse(url.substringAfter("?body=").contains("&"))
}

@Test
fun bugReportUrl_bodyDecodesToOutlineWithEnvironmentDetails() {
val url = bugReportUrl(appVersion = "0.12.3", androidVersion = "14", apiLevel = 34)
val body = URLDecoder.decode(url.substringAfter("?body="), StandardCharsets.UTF_8.name())

assertTrue(body.startsWith("## Description\n"))
assertTrue(body.contains("## Steps to reproduce\n"))
assertTrue(body.contains("## Expected behavior\n"))
assertTrue(body.endsWith("## Environment\n\n- App version: 0.12.3\n- Android version: 14 (API 34)"))
}

@Test
fun bugReportUrl_encodesReservedCharactersInVersions() {
val url = bugReportUrl(appVersion = "1.0-rc&1 #2", androidVersion = "?", apiLevel = 1)
val encoded = url.substringAfter("?body=")
val body = URLDecoder.decode(encoded, StandardCharsets.UTF_8.name())

assertFalse(encoded.contains("&"))
assertFalse(encoded.contains("#"))
assertFalse(encoded.contains("?"))
assertTrue(body.contains("- App version: 1.0-rc&1 #2\n- Android version: ? (API 1)"))
}
}
Loading