Skip to content

Commit

Permalink
Remove GA
Browse files Browse the repository at this point in the history
Lots of good reasons to do this, but the particular issue right now is
that it uses PendingIntent with the wrong flags for recent SDK versions,
and updating is a hassle in itself, so it's far easier to strip it
entirely.
  • Loading branch information
pimterry committed Apr 10, 2023
1 parent 71b3423 commit 2c2fe1e
Show file tree
Hide file tree
Showing 5 changed files with 1 addition and 82 deletions.
4 changes: 1 addition & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

buildConfigField "String", "SENTRY_DSN", "null"
buildConfigField "String", "GA_ID", "null"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
buildConfigField "String", "SENTRY_DSN", "\"https://[email protected]/1809979\""
buildConfigField "String", "GA_ID", "\"UA-117670723-3\""
}
}
lintOptions {
Expand Down Expand Up @@ -53,7 +51,7 @@ dependencies {
implementation 'net.swiftzer.semver:semver:1.1.1'
implementation 'io.sentry:sentry-android:1.7.27'
implementation 'org.slf4j:slf4j-nop:1.7.25'
implementation 'com.google.android.gms:play-services-analytics:10.2.4'
implementation 'com.google.android.gms:play-services-base:10.2.4'
implementation 'com.android.installreferrer:installreferrer:1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ import com.android.installreferrer.api.InstallReferrerClient
import com.android.installreferrer.api.InstallReferrerClient.InstallReferrerResponse
import com.android.installreferrer.api.InstallReferrerStateListener
import com.beust.klaxon.Klaxon
import com.google.android.gms.analytics.GoogleAnalytics
import com.google.android.gms.analytics.HitBuilders
import com.google.android.gms.analytics.Tracker
import io.sentry.Sentry
import io.sentry.android.AndroidSentryClientFactory
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -46,9 +43,6 @@ private val bootTime = (System.currentTimeMillis() - android.os.SystemClock.elap

class HttpToolkitApplication : Application() {

private var analytics: GoogleAnalytics? = null
private var ga: Tracker? = null

private lateinit var prefs: SharedPreferences
private var vpnWasKilled: Boolean = false

Expand Down Expand Up @@ -76,13 +70,6 @@ class HttpToolkitApplication : Application() {
Sentry.init(BuildConfig.SENTRY_DSN, AndroidSentryClientFactory(this))
}

if (BuildConfig.GA_ID != null) {
analytics = GoogleAnalytics.getInstance(this)
ga = analytics!!.newTracker(BuildConfig.GA_ID)
ga!!.setAnonymizeIp(true)
resumeEvents() // Resume events on app startup, in case they were paused and we crashed
}

// Check if we've been recreated unexpectedly, with no crashes in the meantime:
val appCrashed = prefs.getBoolean(APP_CRASHED_PREF, false)
prefs.edit().putBoolean(APP_CRASHED_PREF, false).apply()
Expand Down Expand Up @@ -213,37 +200,6 @@ class HttpToolkitApplication : Application() {
prefs.edit().putStringSet("intercepted-ports", ports.map(Int::toString).toSet()).apply()
}

fun trackScreen(name: String) {
ga?.setScreenName(name)
ga?.send(HitBuilders.EventBuilder().build())
}

fun clearScreen() {
ga?.setScreenName(null)
}

fun trackEvent(category: String, action: String) {
ga?.send(
HitBuilders.EventBuilder()
.setCategory(category)
.setAction(action)
.build()
)
}

/**
* Unclear if the below two actually work - analytics on devices with google play is
* managed by the device itself, not the app. Worth a try though.
*/

fun pauseEvents() {
analytics?.setLocalDispatchPeriod(0) // Don't dispatch events for now
}

fun resumeEvents() {
analytics?.setLocalDispatchPeriod(120) // Set dispatching back to Android default
}

suspend fun isUpdateRequired(): Boolean {
return withContext(Dispatchers.IO) {
if (wasInstalledFromStore(this@HttpToolkitApplication)) {
Expand Down
25 changes: 0 additions & 25 deletions app/src/main/java/tech/httptoolkit/android/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume")
app.trackScreen("Main")
}

override fun onPause() {
super.onPause()
Log.d(TAG, "onPause")
app.clearScreen()
this.lastPauseTime = System.currentTimeMillis()
}

Expand All @@ -169,7 +167,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
// ACTION_VIEW means that somebody had the app installed, and scanned the barcode with
// a separate barcode app anyway (or opened the QR code URL in a browser)
intent.action == Intent.ACTION_VIEW -> {
app.trackEvent("Setup", "action-view")
if (app.lastProxy != null && isVpnConfigured()) {
Log.i(TAG, "Showing prompt for ACTION_VIEW intent")

Expand Down Expand Up @@ -201,17 +198,14 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
// RC setup API, used by ADB to enable/disable without prompts.
// Permission required, checked for via activity-alias in the manifest
isRCIntent && intent.action == ACTIVATE_INTENT -> {
app.trackEvent("Setup", "rc-activate")
launch { connectToVpnFromUrl(intent.data!!) }
}
isRCIntent && intent.action == DEACTIVATE_INTENT -> {
app.trackEvent("Setup", "rc-deactivate")
disconnect()
}

intent.action == "android.intent.action.MAIN" -> {
// The app is being opened - nothing to do here
app.trackEvent("Setup", "ui-opened")
}

else -> Log.w(TAG, "Ignoring unknown intent. Action ${
Expand Down Expand Up @@ -320,7 +314,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
}

private fun scanCode() {
app.trackEvent("Button", "scan-code")
startActivityForResult(Intent(this, ScanActivity::class.java), SCAN_REQUEST)
}

Expand All @@ -332,7 +325,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {

withContext(Dispatchers.Main) { updateUi() }

app.trackEvent("Button", "start-vpn")
val vpnIntent = VpnService.prepare(this)
Log.i(TAG, if (vpnIntent != null) "got intent" else "no intent")
val vpnNotConfigured = vpnIntent != null
Expand Down Expand Up @@ -382,15 +374,12 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
mainState = MainState.DISCONNECTING
updateUi()

app.trackEvent("Button", "stop-vpn")
startService(Intent(this, ProxyVpnService::class.java).apply {
action = STOP_VPN_ACTION
})
}

private suspend fun reconnect(lastProxy: ProxyConfig) {
app.trackEvent("Button", "reconnect")

withContext(Dispatchers.Main) {
mainState = MainState.CONNECTING
updateUi()
Expand All @@ -414,7 +403,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
e.printStackTrace()

withContext(Dispatchers.Main) {
app.trackEvent("Setup", "reconnect-failed")
mainState = MainState.FAILED
updateUi()
}
Expand All @@ -427,14 +415,12 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
}

private fun resetAfterFailure() {
app.trackEvent("Button", "try-again")
currentProxyConfig = null
mainState = MainState.DISCONNECTED
updateUi()
}

private fun openDocs() {
app.trackEvent("Button", "open-docs")
launchBrowser("httptoolkit.tech/docs/guides/android")
}

Expand All @@ -457,8 +443,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
}

private fun testInterception() {
app.trackEvent("Button", "test-interception")

val certIsSystemTrusted = whereIsCertTrusted(
this.currentProxyConfig!! // Safe!! because you can only run tests while connected
) == "system"
Expand Down Expand Up @@ -520,20 +504,17 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
Log.i(TAG, "Installing cert")
ensureCertificateTrusted(currentProxyConfig!!)
} else if (requestCode == INSTALL_CERT_REQUEST) {
app.trackEvent("Setup", "installed-cert-successfully")
startVpn()
} else if (requestCode == SCAN_REQUEST && data != null) {
val url = data.getStringExtra(SCANNED_URL_EXTRA)!!
launch { connectToVpnFromUrl(url) }
} else if (requestCode == PICK_APPS_REQUEST) {
app.trackEvent("Setup", "picked-apps")
val unselectedApps = data!!.getStringArrayExtra(UNSELECTED_APPS_EXTRA)!!.toSet()
if (unselectedApps != app.uninterceptedApps) {
app.uninterceptedApps = unselectedApps
if (isVpnActive()) startVpn()
}
} else if (requestCode == PICK_PORTS_REQUEST) {
app.trackEvent("Setup", "picked-ports")
val selectedPorts = data!!.getIntArrayExtra(SELECTED_PORTS_EXTRA)!!.toSet()
if (selectedPorts != app.interceptedPorts) {
app.interceptedPorts = selectedPorts
Expand Down Expand Up @@ -561,7 +542,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
// via prompt. We redo the manual step regardless: either (on modern Android) manual is
// required so this is just reshowing the instructions, or it was automated but that's not
// working for some reason, in which case manual setup is a best-effort fallback.
app.trackEvent("Setup", "cert-install-failed")
launch { promptToManuallyInstallCert(currentProxyConfig!!.certificate, repeatPrompt = true) }
} else {
Sentry.capture("Non-OK result $resultCode for requestCode $requestCode")
Expand Down Expand Up @@ -613,7 +593,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
e.printStackTrace()

withContext(Dispatchers.Main) {
app.trackEvent("Setup", "connect-failed")
mainState = MainState.FAILED
updateUi()
}
Expand All @@ -633,11 +612,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
private fun ensureCertificateTrusted(proxyConfig: ProxyConfig) {
val existingTrust = whereIsCertTrusted(proxyConfig)
if (existingTrust == null) {
app.trackEvent("Setup", "installing-cert")
Log.i(TAG, "Certificate not trusted, prompting to install")

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
app.trackEvent("Setup", "installing-cert-manually")
// Android 11+, with no trusted cert: we need to download the cert to Downloads and
// then tell the user how to install it manually:
launch { promptToManuallyInstallCert(proxyConfig.certificate) }
Expand All @@ -646,14 +623,12 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
// CA store. Notably, if the cert is already installed as a system cert but
// disabled, this will get triggered, and will enable the cert, rather than adding
// a normal user cert.
app.trackEvent("Setup", "installing-cert-automatically")
val certInstallIntent = KeyChain.createInstallIntent()
certInstallIntent.putExtra(EXTRA_NAME, "HTTP Toolkit CA")
certInstallIntent.putExtra(EXTRA_CERTIFICATE, proxyConfig.certificate.encoded)
startActivityForResult(certInstallIntent, INSTALL_CERT_REQUEST)
}
} else {
app.trackEvent("Setup", "existing-$existingTrust-cert")
Log.i(TAG, "Certificate already trusted, continuing")
onActivityResult(INSTALL_CERT_REQUEST, RESULT_OK, null)
}
Expand Down
7 changes: 0 additions & 7 deletions app/src/main/java/tech/httptoolkit/android/ProxyVpnService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ class ProxyVpnService : VpnService(), IProtectSocket {

override fun onRevoke() {
super.onRevoke()
app.trackEvent("VPN", "vpn-revoked")
Log.i(TAG, "onRevoke called")
stopVpn()
}
Expand Down Expand Up @@ -166,8 +165,6 @@ class ProxyVpnService : VpnService(), IProtectSocket {

if (this.vpnInterface != null) return false // Already running, do nothing

app.pauseEvents() // Try not to send events while the VPN is active, it's unnecessary noise
app.trackEvent("VPN", "vpn-started")
val vpnInterface = Builder()
.addAddress(VPN_IP_ADDRESS, 32)
.addRoute(ALL_ROUTES, 0)
Expand Down Expand Up @@ -269,7 +266,6 @@ class ProxyVpnService : VpnService(), IProtectSocket {
Log.i(TAG, "VPN stopping for restart...")

if (vpnRunnable != null) {
app.trackEvent("VPN", "vpn-stopped-for-restart")
vpnRunnable!!.stop()
vpnRunnable = null
}
Expand All @@ -289,9 +285,6 @@ class ProxyVpnService : VpnService(), IProtectSocket {
Log.i(TAG, "VPN stopping...")

if (vpnRunnable != null) {
app.trackEvent("VPN", "vpn-stopped")
app.resumeEvents()

vpnRunnable!!.stop()
vpnRunnable = null
}
Expand Down
3 changes: 0 additions & 3 deletions app/src/main/java/tech/httptoolkit/android/ScanActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,13 @@ class ScanActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
public override fun onResume() {
super.onResume()

app!!.trackScreen("Scan")
scannerView!!.setResultHandler(this)
scannerView!!.startCamera()
}

public override fun onPause() {
super.onPause()

app!!.clearScreen()
scannerView!!.stopCamera()
}

Expand Down Expand Up @@ -76,7 +74,6 @@ class ScanActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
}

Log.v(TAG, "Scanned $url")
app!!.trackEvent("Setup", "tag-scanned")

setResult(RESULT_OK, Intent().let { intent ->
intent.putExtra(SCANNED_URL_EXTRA, url)
Expand Down

0 comments on commit 2c2fe1e

Please sign in to comment.