diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 708b0c3c21..4eb1528111 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -33,8 +33,7 @@ plugins {
id("kotlin-parcelize")
id("androidx.navigation.safeargs.kotlin")
id("com.itsaky.androidide.desugaring")
- alias(libs.plugins.sentry)
- alias(libs.plugins.google.services)
+alias(libs.plugins.google.services)
}
fun propOrEnv(name: String): String =
@@ -79,12 +78,8 @@ android {
buildTypes {
debug {
signingConfig = signingConfigs.getByName("debug")
- manifestPlaceholders["sentryDsn"] =
- props.getProperty("sentryDsnDebug") ?: propOrEnv("SENTRY_DSN_DEBUG")
}
release {
- manifestPlaceholders["sentryDsn"] =
- props.getProperty("sentryDsnRelease") ?: propOrEnv("SENTRY_DSN_RELEASE")
}
}
@@ -147,10 +142,6 @@ android {
}
}
-sentry {
- includeProguardMapping = false
-}
-
kapt { arguments { arg("eventBusIndex", "${BuildConfig.PACKAGE_NAME}.events.AppEventsIndex") } }
desugaring {
@@ -321,11 +312,6 @@ dependencies {
implementation(libs.koin.android)
implementation(libs.androidx.security.crypto)
- // Sentry Android SDK (core + replay for quality configuration)
- implementation(libs.sentry.core)
- implementation(libs.sentry.android.core)
- implementation(libs.sentry.android.replay)
-
// Firebase Analytics
implementation(platform(libs.firebase.bom))
implementation(libs.firebase.analytics)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1aa4f452d0..ebb87bb8cb 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -124,49 +124,6 @@
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:windowSoftInputMode="adjustResize" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
logger.error("Failed to get WorkManager instance after storage validation", error)
- Sentry.captureException(error)
}
}
@@ -167,7 +165,6 @@ internal object CredentialProtectedApplicationLoader : ApplicationLoader {
}
writeException(exception)
- Sentry.captureException(exception)
runCatching {
val intent = Intent()
@@ -179,7 +176,6 @@ internal object CredentialProtectedApplicationLoader : ApplicationLoader {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
IDEApplication.instance.startActivity(intent)
}.onFailure { error ->
- Sentry.captureException(error)
logger.error("Unable to start crash handler activity", error)
}
@@ -192,12 +188,6 @@ internal object CredentialProtectedApplicationLoader : ApplicationLoader {
runCatching {
writeException(exception)
- Sentry.withScope { scope ->
- scope.setTag("plugin_crash", "true")
- scope.setTag("plugin_id", pluginId)
- Sentry.captureException(exception)
- }
-
val pluginManager = PluginManager.getInstance() ?: return
val result = pluginManager.recordPluginCrash(pluginId)
@@ -338,7 +328,6 @@ internal object CredentialProtectedApplicationLoader : ApplicationLoader {
}
}
} catch (e: Exception) {
- Sentry.captureException(e)
logger.error("Failed to initialize plugin system", e)
}
}
diff --git a/app/src/main/java/com/itsaky/androidide/app/DeviceProtectedApplicationLoader.kt b/app/src/main/java/com/itsaky/androidide/app/DeviceProtectedApplicationLoader.kt
index deb40e1786..7629ba41b2 100644
--- a/app/src/main/java/com/itsaky/androidide/app/DeviceProtectedApplicationLoader.kt
+++ b/app/src/main/java/com/itsaky/androidide/app/DeviceProtectedApplicationLoader.kt
@@ -13,16 +13,12 @@ import com.itsaky.androidide.events.LspApiEventsIndex
import com.itsaky.androidide.events.LspJavaEventsIndex
import com.itsaky.androidide.events.ProjectsApiEventsIndex
import com.itsaky.androidide.handlers.CrashEventSubscriber
-import com.itsaky.androidide.handlers.SentryDiagnosticsContext
import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE
import com.itsaky.androidide.ui.themes.IThemeManager
import com.itsaky.androidide.utils.Environment
import com.itsaky.androidide.utils.FeatureFlags
import com.termux.shared.reflection.ReflectionUtils
import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
-import io.sentry.Sentry
-import io.sentry.SentryReplayOptions.SentryReplayQuality
-import io.sentry.android.core.SentryAndroid
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -67,18 +63,6 @@ internal object DeviceProtectedApplicationLoader :
),
)
- SentryAndroid.init(app) { options ->
- // Reduce replay quality to LOW to prevent OOM
- // This reduces screenshot compression to 10 and bitrate to 50kbps
- // (defaults to MEDIUM quality)
- options.sessionReplay.quality = SentryReplayQuality.LOW
- options.environment =
- if (BuildConfig.DEBUG) IDEApplication.SENTRY_ENV_DEV else IDEApplication.SENTRY_ENV_PROD
-
- // Enrich every Sentry event with app-specific diagnostic context.
- SentryDiagnosticsContext.install(options)
- }
-
ShizukuSettings.initialize()
EventBus
@@ -120,10 +104,6 @@ internal object DeviceProtectedApplicationLoader :
thread: Thread,
exception: Throwable,
) {
- // we can't write logs to files, nor we can show the crash handler
- // activity to the user. Just report to Sentry and exit.
-
- Sentry.captureException(exception)
IDEApplication.instance.uncaughtExceptionHandler?.uncaughtException(thread, exception)
exitProcess(EXIT_CODE_CRASH)
}
diff --git a/app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt b/app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt
index b673341529..1c86f6f8eb 100755
--- a/app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt
+++ b/app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt
@@ -29,7 +29,6 @@ import androidx.work.Configuration
import com.itsaky.androidide.BuildConfig
import com.itsaky.androidide.di.coreModule
import com.itsaky.androidide.di.pluginModule
-import com.itsaky.androidide.handlers.SentryDiagnosticsContext
import com.itsaky.androidide.plugins.manager.core.PluginManager
import com.itsaky.androidide.treesitter.TreeSitter
import com.itsaky.androidide.utils.RecyclableObjectPool
@@ -37,7 +36,6 @@ import com.itsaky.androidide.utils.VMUtils
import com.itsaky.androidide.utils.isAtLeastR
import com.itsaky.androidide.utils.isTestMode
import com.topjohnwu.superuser.Shell
-import io.sentry.Sentry
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
@@ -85,9 +83,6 @@ class IDEApplication :
) {
if (intent?.action == Intent.ACTION_USER_UNLOCKED) {
runCatching { unregisterReceiver(this) }
- // Stamp the unlock time so Sentry's boot_mode context reflects the
- // live state and can report the direct-boot locked duration.
- SentryDiagnosticsContext.onUserUnlocked()
coroutineScope.launch(Dispatchers.Default) {
logger.info("Device unlocked! Loading all components...")
CredentialProtectedApplicationLoader.load(this@IDEApplication)
@@ -99,9 +94,6 @@ class IDEApplication :
companion object {
private val logger = LoggerFactory.getLogger(IDEApplication::class.java)
- const val SENTRY_ENV_DEV = "development"
- const val SENTRY_ENV_PROD = "production"
-
@JvmStatic
@SuppressLint("StaticFieldLeak")
lateinit var instance: IDEApplication
@@ -131,7 +123,6 @@ class IDEApplication :
TreeSitter.loadLibrary()
} catch (e: UnsatisfiedLinkError) {
- Sentry.captureException(e)
logger.warn("Failed to load native libraries", e)
}
}
@@ -180,7 +171,6 @@ class IDEApplication :
// In case any of the components fail to initialize there, it may lead
// to ANRs when the IDE is launched after device reboot.
// https://appdevforall.atlassian.net/browse/ADFA-2026
- // https://appdevforall-inc-9p.sentry.io/issues/6860179170/events/7177c576e7b3491c9e9746c76f806d37/
ensureKoinStarted()
@@ -223,7 +213,6 @@ class IDEApplication :
if (isFinalizerWatchdogTimeout(thread, exception)) {
logger.warn("Non-fatal: FinalizerWatchdogDaemon timeout (suppressed crash)", exception)
- Sentry.captureException(exception)
return
}
diff --git a/app/src/main/java/com/itsaky/androidide/assets/AssetsInstallationHelper.kt b/app/src/main/java/com/itsaky/androidide/assets/AssetsInstallationHelper.kt
index 3efc221669..77e1fa5565 100644
--- a/app/src/main/java/com/itsaky/androidide/assets/AssetsInstallationHelper.kt
+++ b/app/src/main/java/com/itsaky/androidide/assets/AssetsInstallationHelper.kt
@@ -52,7 +52,6 @@ object AssetsInstallationHelper {
data class Failure(
val cause: Throwable?,
val errorMessage: String? = cause?.message,
- val shouldReportToSentry: Boolean = true
) : Result
}
@@ -90,7 +89,7 @@ object AssetsInstallationHelper {
}
logger.error("Failed to install assets", e)
onProgress(Progress(msg))
- return@withContext Result.Failure(cause, errorMessage = msg, shouldReportToSentry = !isMissingAsset)
+ return@withContext Result.Failure(cause, errorMessage = msg)
}
return@withContext Result.Success
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/RecentProjectsFragment.kt b/app/src/main/java/com/itsaky/androidide/fragments/RecentProjectsFragment.kt
index 129fa28462..a64b9a58d1 100644
--- a/app/src/main/java/com/itsaky/androidide/fragments/RecentProjectsFragment.kt
+++ b/app/src/main/java/com/itsaky/androidide/fragments/RecentProjectsFragment.kt
@@ -38,7 +38,6 @@ import com.itsaky.androidide.viewmodel.FilterState
import com.itsaky.androidide.viewmodel.RecentProjectsViewModel
import com.itsaky.androidide.viewmodel.SortCriteria
import com.itsaky.androidide.ui.ProjectInfoBottomSheet
-import io.sentry.Sentry
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.debounce
@@ -324,8 +323,7 @@ class RecentProjectsFragment : BaseFragment() {
if (validProjects.isEmpty()) return@launch
loadProjectsIntoViewModel(validProjects)
- } catch (e: Throwable) {
- Sentry.captureException(e)
+ } catch (_: Throwable) {
}
}
}
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/debug/DebuggerFragment.kt b/app/src/main/java/com/itsaky/androidide/fragments/debug/DebuggerFragment.kt
index 4df5333c01..8e7c037180 100644
--- a/app/src/main/java/com/itsaky/androidide/fragments/debug/DebuggerFragment.kt
+++ b/app/src/main/java/com/itsaky/androidide/fragments/debug/DebuggerFragment.kt
@@ -33,7 +33,6 @@ import com.itsaky.androidide.utils.viewLifecycleScope
import com.itsaky.androidide.viewmodel.DebuggerConnectionState
import com.itsaky.androidide.viewmodel.DebuggerViewModel
import com.itsaky.androidide.viewmodel.WADBConnectionViewModel
-import io.sentry.Sentry
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
@@ -423,8 +422,7 @@ class ThreadSelectorListAdapter(
if (view.isAttachedToWindow) {
onItemLongClick.invoke(item, position, view)
}
- } catch (e: Exception) {
- Sentry.captureException(e)
+ } catch (_: Exception) {
}
}
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt b/app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt
index 750b6ac2fb..9ed7d6a911 100644
--- a/app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt
+++ b/app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt
@@ -55,7 +55,6 @@ import com.itsaky.androidide.utils.isAtLeastR
import com.itsaky.androidide.utils.viewLifecycleScope
import com.itsaky.androidide.viewmodel.InstallationState
import com.itsaky.androidide.viewmodel.InstallationViewModel
-import io.sentry.Sentry
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
@@ -404,8 +403,7 @@ class PermissionsFragment :
val privacyPolicyUrl = getString(R.string.privacy_policy_url)
val intent = Intent(Intent.ACTION_VIEW, privacyPolicyUrl.toUri())
startActivity(intent)
- } catch (e: Exception) {
- Sentry.captureException(e)
+ } catch (_: Exception) {
}
}
diff --git a/app/src/main/java/com/itsaky/androidide/handlers/CrashEventSubscriber.kt b/app/src/main/java/com/itsaky/androidide/handlers/CrashEventSubscriber.kt
index 158ebf4f93..0343554d7c 100644
--- a/app/src/main/java/com/itsaky/androidide/handlers/CrashEventSubscriber.kt
+++ b/app/src/main/java/com/itsaky/androidide/handlers/CrashEventSubscriber.kt
@@ -5,7 +5,6 @@ import com.blankj.utilcode.util.ActivityUtils.startActivity
import com.blankj.utilcode.util.ThrowableUtils.getFullStackTrace
import com.itsaky.androidide.activities.CrashHandlerActivity
import com.itsaky.androidide.eventbus.events.editor.ReportCaughtExceptionEvent
-import io.sentry.Sentry
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.slf4j.LoggerFactory
@@ -19,25 +18,15 @@ class CrashEventSubscriber {
@Subscribe(threadMode = ThreadMode.BACKGROUND)
fun onReportCaughtException(ev: ReportCaughtExceptionEvent) {
try {
- Sentry.configureScope { scope ->
- ev.extras.forEach { (k, v) -> scope.setTag(k, v) }
- ev.message?.let { scope.setExtra("message", it) }
- }
- Sentry.captureException(ev.throwable)
+ val intent = Intent()
+ intent.action = CrashHandlerActivity.REPORT_ACTION
+ intent.putExtra(CrashHandlerActivity.TRACE_KEY, getFullStackTrace(ev.throwable))
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ startActivity(intent)
- try {
- val intent = Intent()
- intent.action = CrashHandlerActivity.REPORT_ACTION
- intent.putExtra(CrashHandlerActivity.TRACE_KEY, getFullStackTrace(ev.throwable))
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- startActivity(intent)
-
- exitProcess(EXIT_CODE_CRASH)
- } catch (error: Throwable) {
- log.error("Unable to show crash handler activity", error)
- }
- } catch (t: Throwable) {
- log.error("Failed to forward exception to Sentry", t)
+ exitProcess(EXIT_CODE_CRASH)
+ } catch (error: Throwable) {
+ log.error("Unable to show crash handler activity", error)
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/itsaky/androidide/handlers/SentryDiagnosticsContext.kt b/app/src/main/java/com/itsaky/androidide/handlers/SentryDiagnosticsContext.kt
deleted file mode 100644
index 640b797624..0000000000
--- a/app/src/main/java/com/itsaky/androidide/handlers/SentryDiagnosticsContext.kt
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * This file is part of AndroidIDE.
- *
- * AndroidIDE is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * AndroidIDE is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with AndroidIDE. If not, see .
- *
- */
-
-package com.itsaky.androidide.handlers
-
-import android.content.pm.ApplicationInfo
-import android.os.SystemClock
-import com.blankj.utilcode.util.AppUtils
-import com.blankj.utilcode.util.DeviceUtils
-import com.itsaky.androidide.app.IDEApplication
-import com.itsaky.androidide.app.configuration.IDEBuildConfigProvider
-import com.itsaky.androidide.buildinfo.BuildInfo
-import com.itsaky.androidide.plugins.manager.core.PluginManager
-import com.itsaky.androidide.utils.BuildInfoUtils
-import com.termux.shared.android.PackageUtils
-import com.termux.shared.android.SELinuxUtils
-import io.sentry.EventProcessor
-import io.sentry.Hint
-import io.sentry.SentryEvent
-import io.sentry.SentryOptions
-import org.slf4j.LoggerFactory
-
-/**
- * Enriches every Sentry event with app-specific diagnostic context (SELinux
- * labels, boot mode, install location, signing certificate, active plugins,
- * release/ABI/device posture).
- *
- * The context is attached through a single [EventProcessor] registered in
- * [io.sentry.android.core.SentryAndroid.init]. Running at capture time means a
- * single processor sees the live boot state and the currently loaded plugins
- * for fatal crashes, caught exceptions and plugin crashes alike, with no
- * per-call-site wiring.
- *
- * Every field is collected inside its own [runCatching] so that a single
- * failing collector (e.g. an SELinux read denied by policy, or credential
- * protected storage being inaccessible in direct boot) drops only that one
- * field — the event is still reported with everything else intact.
- *
- * No source code or project file paths are ever read. The SELinux file-context
- * collector keeps only the returned security label, not the directory path.
- *
- * @author Hal Eisen
- */
-object SentryDiagnosticsContext {
-
- private val log = LoggerFactory.getLogger(SentryDiagnosticsContext::class.java)
-
- /** Process/boot start stamp, used to compute the direct-boot locked duration. */
- private val bootElapsedStartMs = SystemClock.elapsedRealtime()
-
- /** Elapsed-time stamp of when the user credential-unlocked the device, if observed. */
- @Volatile
- private var userUnlockedElapsedMs: Long? = null
-
- /** Whether the app process started while the device was still credential-locked. */
- @Volatile
- private var startedInDirectBoot = false
-
- // --- Static per-process values, computed once and cached lazily. ---
-
- private val appInfo: ApplicationInfo? by lazy {
- val app = IDEApplication.instance
- PackageUtils.getApplicationInfoForPackage(app, app.packageName)
- }
-
- private val seInfo: String? by lazy {
- appInfo?.let { PackageUtils.getApplicationInfoSeInfoForPackage(it) }
- }
-
- private val signingDigest: String? by lazy {
- val app = IDEApplication.instance
- PackageUtils.getSigningCertificateSHA256DigestForPackage(app, app.packageName)
- }
-
- private val installLocation: String? by lazy {
- appInfo?.let {
- if (PackageUtils.isAppInstalledOnExternalStorage(it)) "external" else "internal"
- }
- }
-
- /**
- * Registers the diagnostics [EventProcessor] on the given Sentry [options].
- * Call once from within `SentryAndroid.init`.
- */
- fun install(options: SentryOptions) {
- // Capture whether we started locked at install time; install() runs from
- // DeviceProtectedApplicationLoader, which is reachable in direct boot.
- startedInDirectBoot = runCatching { !IDEApplication.instance.isUserUnlocked }.getOrDefault(false)
-
- options.addEventProcessor(object : EventProcessor {
- override fun process(event: SentryEvent, hint: Hint): SentryEvent {
- runCatching { enrich(event) }.onFailure { log.warn("Failed to enrich Sentry event", it) }
- return event
- }
- })
- }
-
- /**
- * Stamps the moment the device transitioned to credential-unlocked, so the
- * direct-boot locked duration can be reported. Idempotent — only the first
- * unlock is recorded.
- */
- fun onUserUnlocked() {
- if (userUnlockedElapsedMs == null) {
- userUnlockedElapsedMs = SystemClock.elapsedRealtime()
- }
- }
-
- private fun enrich(event: SentryEvent) {
- val app = runCatching { IDEApplication.instance }.getOrNull() ?: return
-
- // ① SELinux contexts (process, private-data-dir file label, seinfo).
- context(event, "selinux") {
- buildMap {
- runCatching { SELinuxUtils.getContext() }.getOrNull()?.let { put("process_context", it) }
- runCatching { SELinuxUtils.getFileContext(app.filesDir.absolutePath) }
- .getOrNull()?.let { put("file_context", it) }
- runCatching { seInfo }.getOrNull()?.let { put("seinfo", it) }
- }
- }
-
- // ② Boot mode, queried live, plus the locked duration if we started locked.
- tag(event, "boot_mode") {
- if (app.isUserUnlocked) "credential_unlocked" else "direct_boot"
- }
- if (startedInDirectBoot) {
- tag(event, "boot_locked_duration_ms") {
- val end = userUnlockedElapsedMs ?: SystemClock.elapsedRealtime()
- (end - bootElapsedStartMs).toString()
- }
- }
-
- // ③ Install location (internal vs external/SD).
- tag(event, "install_location") { installLocation }
-
- // ④ Signing certificate digest + official/unofficial build flag.
- tag(event, "signing_sha256") { signingDigest }
- tag(event, "signing_official") { BuildInfoUtils.isOfficialBuild(app).toString() }
-
- // ⑤ Active plugins (enabled + loaded) with version and recent crash count.
- context(event, "active_plugins") {
- val pm = PluginManager.getInstance() ?: return@context null
- val plugins = pm.getAllPlugins()
- .filter { it.isEnabled && it.isLoaded }
- .map { info ->
- mapOf(
- "id" to info.metadata.id,
- "version" to info.metadata.version,
- "min_ide_version" to info.metadata.minIdeVersion,
- "crash_count" to runCatching {
- pm.crashTracker.getCrashCount(info.metadata.id)
- }.getOrDefault(0),
- )
- }
- mapOf("count" to plugins.size, "plugins" to plugins)
- }
-
- // A — release identifier + version code.
- tag(event, "app_version_name") { BuildInfo.VERSION_NAME_SIMPLE }
- tag(event, "app_version_code") { AppUtils.getAppVersionCode().toString() }
- tag(event, "app_git_commit") { BuildInfo.CI_GIT_COMMIT_HASH }
- tag(event, "app_ci_build") { BuildInfo.CI_BUILD.toString() }
-
- // B — process ABI / variant.
- val buildConfig = IDEBuildConfigProvider.getInstance()
- tag(event, "abi") { buildConfig.cpuAbiName }
- tag(event, "cpu_arch") { buildConfig.cpuArch.name }
-
- // H — device posture (emulator vs physical, rooted).
- tag(event, "device_emulator") { DeviceUtils.isEmulator().toString() }
- tag(event, "device_rooted") { DeviceUtils.isDeviceRooted().toString() }
- }
-
- /** Sets a single tag, guarded so a failing collector drops only that tag. */
- private inline fun tag(event: SentryEvent, key: String, value: () -> String?) {
- runCatching { value()?.let { event.setTag(key, it) } }
- .onFailure { log.debug("Sentry diagnostics: dropped tag '{}'", key, it) }
- }
-
- /**
- * Attaches a structured context group, guarded so a failing collector drops
- * only that group. Empty/null maps are skipped.
- */
- private inline fun context(event: SentryEvent, key: String, value: () -> Map?) {
- runCatching { value()?.takeIf { it.isNotEmpty() }?.let { event.contexts.put(key, it) } }
- .onFailure { log.debug("Sentry diagnostics: dropped context '{}'", key, it) }
- }
-}
diff --git a/app/src/main/java/com/itsaky/androidide/repositories/BreakpointRepository.kt b/app/src/main/java/com/itsaky/androidide/repositories/BreakpointRepository.kt
index e361d9f799..82a3d96819 100644
--- a/app/src/main/java/com/itsaky/androidide/repositories/BreakpointRepository.kt
+++ b/app/src/main/java/com/itsaky/androidide/repositories/BreakpointRepository.kt
@@ -9,7 +9,6 @@ import com.itsaky.androidide.lsp.debug.model.PositionalBreakpoint
import com.itsaky.androidide.lsp.debug.model.MethodBreakpoint
import com.itsaky.androidide.tooling.api.util.RuntimeTypeAdapterFactory
import com.itsaky.androidide.utils.Environment
-import io.sentry.Sentry
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
@@ -105,7 +104,6 @@ object BreakpointRepository {
"Failed to save breakpoints to file: ${file.absolutePath}",
e
)
- Sentry.captureException(e)
}
}
}
diff --git a/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.kt b/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.kt
index 06f2e0d0b8..dba78c4d31 100644
--- a/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.kt
+++ b/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.kt
@@ -71,7 +71,6 @@ import com.itsaky.androidide.tooling.events.ProgressEvent
import com.itsaky.androidide.utils.Environment
import com.itsaky.androidide.utils.FeatureFlags
import com.termux.shared.termux.shell.command.environment.TermuxShellEnvironment
-import io.sentry.Sentry
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -284,7 +283,6 @@ class GradleBuildService :
} else {
// log if the error is not due to the stream being closed
log.error("Failed to shutdown Tooling API server", err)
- Sentry.captureException(err)
}
}
}
@@ -388,7 +386,6 @@ class GradleBuildService :
}
}.onFailure { err ->
log.error("Failed to auto-tune Gradle build", err)
- Sentry.captureException(err)
}.getOrDefault(null)
} else {
null
diff --git a/app/src/main/java/com/itsaky/androidide/viewmodel/InstallationViewModel.kt b/app/src/main/java/com/itsaky/androidide/viewmodel/InstallationViewModel.kt
index 2da418b61e..1acf8ab2c3 100644
--- a/app/src/main/java/com/itsaky/androidide/viewmodel/InstallationViewModel.kt
+++ b/app/src/main/java/com/itsaky/androidide/viewmodel/InstallationViewModel.kt
@@ -20,7 +20,6 @@ import com.itsaky.androidide.viewmodel.InstallationState.InstallationError
import com.itsaky.androidide.viewmodel.InstallationState.InstallationGranted
import com.itsaky.androidide.viewmodel.InstallationState.InstallationPending
import com.itsaky.androidide.viewmodel.InstallationState.Installing
-import io.sentry.Sentry
import kotlin.coroutines.cancellation.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -91,9 +90,6 @@ class InstallationViewModel : ViewModel() {
_state.update { InstallationComplete }
}
is AssetsInstallationHelper.Result.Failure -> {
- if (result.shouldReportToSentry) {
- result.cause?.let { Sentry.captureException(it) }
- }
val errorMsg = result.errorMessage
?: context.getString(R.string.title_installation_failed)
_events.emit(InstallationEvent.ShowError(errorMsg))
@@ -108,7 +104,6 @@ class InstallationViewModel : ViewModel() {
_state.update { InstallationPending }
throw e
}
- Sentry.captureException(e)
log.error("IDE setup installation failed", e)
val errorMsg = e.message ?: context.getString(R.string.unknown_error)
_events.emit(InstallationEvent.ShowError(errorMsg))
diff --git a/app/src/test/java/com/itsaky/androidide/assets/AssetsInstallationHelperTest.kt b/app/src/test/java/com/itsaky/androidide/assets/AssetsInstallationHelperTest.kt
index 81660f0ca9..035cd2194d 100644
--- a/app/src/test/java/com/itsaky/androidide/assets/AssetsInstallationHelperTest.kt
+++ b/app/src/test/java/com/itsaky/androidide/assets/AssetsInstallationHelperTest.kt
@@ -7,7 +7,6 @@ import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import kotlinx.coroutines.runBlocking
-import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
@@ -23,7 +22,7 @@ class AssetsInstallationHelperTest {
}
@Test
- fun `install with missing asset skips sentry`() = runBlocking {
+ fun `install with missing asset wraps in MissingAssetsEntryException`() = runBlocking {
val helper = AssetsInstallationHelper
every {
@@ -38,7 +37,6 @@ class AssetsInstallationHelperTest {
assertTrue("Expected Result.Failure", result is Failure)
val failure = result as Failure
- assertFalse("Should skip Sentry report", failure.shouldReportToSentry)
assertTrue(
"Expected MissingAssetsEntryException as cause",
failure.cause is MissingAssetsEntryException
diff --git a/app/src/test/java/com/itsaky/androidide/handlers/SentryDiagnosticsContextTest.kt b/app/src/test/java/com/itsaky/androidide/handlers/SentryDiagnosticsContextTest.kt
deleted file mode 100644
index fc590e6589..0000000000
--- a/app/src/test/java/com/itsaky/androidide/handlers/SentryDiagnosticsContextTest.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * This file is part of AndroidIDE.
- *
- * AndroidIDE is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * AndroidIDE is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with AndroidIDE. If not, see .
- */
-
-package com.itsaky.androidide.handlers
-
-import com.google.common.truth.Truth.assertThat
-import com.itsaky.androidide.app.IDEApplication
-import com.itsaky.androidide.buildinfo.BuildInfo
-import io.mockk.every
-import io.mockk.mockk
-import io.mockk.mockkObject
-import io.mockk.unmockkAll
-import io.sentry.Hint
-import io.sentry.SentryEvent
-import io.sentry.SentryOptions
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.RobolectricTestRunner
-import java.io.File
-
-/**
- * Verifies that [SentryDiagnosticsContext] enriches events and, crucially, that
- * a single failing field collector never prevents the rest of the event from
- * being reported.
- *
- * @author Hal Eisen
- */
-@RunWith(RobolectricTestRunner::class)
-class SentryDiagnosticsContextTest {
-
- private lateinit var app: IDEApplication
-
- @Before
- fun setUp() {
- // Skip the native-library block in IDEApplication's static initializer.
- System.setProperty("androidide.test.mode", "true")
-
- app = mockk(relaxed = true)
- every { app.packageName } returns "com.itsaky.androidide"
- every { app.filesDir } returns File("/tmp/androidide-test")
- every { app.isUserUnlocked } returns true
-
- mockkObject(IDEApplication.Companion)
- every { IDEApplication.instance } returns app
- }
-
- @After
- fun tearDown() {
- unmockkAll()
- }
-
- /** Installs the processor on a fresh options instance and enriches a new event. */
- private fun enrichNewEvent(): SentryEvent {
- val options = SentryOptions()
- SentryDiagnosticsContext.install(options)
- val processor = options.eventProcessors
- .first { it.javaClass.name.contains("SentryDiagnosticsContext") }
- return processor.process(SentryEvent(), Hint())!!
- }
-
- @Test
- fun `enrich populates diagnostic context on the event`() {
- val event = enrichNewEvent()
-
- // Live boot state and a compile-time release constant are both attached.
- assertThat(event.getTag("boot_mode")).isEqualTo("credential_unlocked")
- assertThat(event.getTag("app_version_name")).isEqualTo(BuildInfo.VERSION_NAME_SIMPLE)
- }
-
- @Test
- fun `a single failing collector never breaks the rest of the event`() {
- // Make the boot-mode collector blow up (simulating e.g. an SELinux denial).
- every { app.isUserUnlocked } throws RuntimeException("read denied")
-
- val event = enrichNewEvent()
-
- // The failing field is simply dropped...
- assertThat(event.getTag("boot_mode")).isNull()
- // ...the event is still returned, with every other field intact.
- assertThat(event.getTag("app_version_name")).isEqualTo(BuildInfo.VERSION_NAME_SIMPLE)
- }
-}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 714f8f7941..0a509a32ec 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -49,8 +49,6 @@ viewpager2 = "1.1.0-beta02"
zoomage = "1.3.1"
monitor = "1.6.1"
monitorVersion = "1.7.2"
-sentry = "8.29.0"
-sentry-gradle-plugin = "5.12.2"
mockk = "1.14.5"
firebase-bom = "33.7.0"
google-services = "4.4.2"
@@ -144,11 +142,6 @@ compose-activity = { module = "androidx.activity:activity-compose", version = "1
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase-bom" }
firebase-analytics = { module = "com.google.firebase:firebase-analytics-ktx" }
-# Sentry
-sentry-core = { module = "io.sentry:sentry", version.ref = "sentry" }
-sentry-android-core = { module = "io.sentry:sentry-android-core", version.ref = "sentry" }
-sentry-android-replay = { module = "io.sentry:sentry-android-replay", version.ref = "sentry" }
-
# AndroidIDE
androidide-ts = { module = "com.itsaky.androidide.treesitter:android-tree-sitter", version.ref = "tree-sitter" }
androidide-ts-java = { module = "com.itsaky.androidide.treesitter:tree-sitter-java", version.ref = "tree-sitter" }
@@ -323,7 +316,6 @@ kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
maven-publish = { id = "com.vanniktech.maven.publish.base", version.ref = "maven-publish-plugin" }
gradle-publish = { id = "com.gradle.plugin-publish", version = "1.2.1" }
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
-sentry = { id = "io.sentry.android.gradle", version.ref = "sentry-gradle-plugin" }
google-services = { id = "com.google.gms.google-services", version.ref = "google-services" }
google-protobuf = { id = "com.google.protobuf", version.ref = "protobuf-plugin" }
rikka-autoresconfig = { id = "dev.rikka.tools.autoresconfig", version = "1.2.2" }
diff --git a/lsp/kotlin/build.gradle.kts b/lsp/kotlin/build.gradle.kts
index 9b16f87796..7ebd5c36a2 100644
--- a/lsp/kotlin/build.gradle.kts
+++ b/lsp/kotlin/build.gradle.kts
@@ -55,8 +55,6 @@ dependencies {
implementation(libs.common.kotlin)
implementation(libs.common.kotlin.coroutines.core)
implementation(libs.common.kotlin.coroutines.android)
- implementation(libs.sentry.android.core)
-
compileOnly(projects.common)
testImplementation(projects.testing.lsp)
diff --git a/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/KotlinLanguageServer.kt b/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/KotlinLanguageServer.kt
index 7ed6946e47..b13027d696 100644
--- a/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/KotlinLanguageServer.kt
+++ b/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/KotlinLanguageServer.kt
@@ -56,7 +56,6 @@ import com.itsaky.androidide.tasks.createJobCancelChecker
import com.itsaky.androidide.utils.DocumentUtils
import com.itsaky.androidide.utils.Environment
import com.itsaky.androidide.utils.ifNotEmpty
-import io.sentry.Sentry
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
@@ -335,7 +334,6 @@ class KotlinLanguageServer : ILanguageServer {
@Subscribe
@Suppress("unused")
fun onBuildCompleted(event: BuildCompletedEvent) {
- Sentry.addBreadcrumb("onBuildCompleted: result=${event.result}")
compiler?.refreshSources()
}
diff --git a/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/CompilationEnvironment.kt b/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/CompilationEnvironment.kt
index e30d462929..2a128ace46 100644
--- a/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/CompilationEnvironment.kt
+++ b/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/CompilationEnvironment.kt
@@ -15,7 +15,6 @@ import com.itsaky.androidide.lsp.kotlin.utils.toVirtualFileOrNull
import com.itsaky.androidide.projects.FileManager
import com.itsaky.androidide.projects.api.Workspace
import com.itsaky.androidide.utils.KeyedDebouncingAction
-import io.sentry.Sentry
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineName
@@ -203,9 +202,7 @@ internal class CompilationEnvironment(
}
fun refreshSources() {
- Sentry.addBreadcrumb("refreshSources (env=$name, modules=${modules.size})")
project.write {
- Sentry.addBreadcrumb("refreshSources(env=$name): in-progress")
ResolutionScopeProvider.getInstance(project).invalidateAll()
modules
.asFlatSequence()
diff --git a/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/index/KtSymbolIndex.kt b/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/index/KtSymbolIndex.kt
index a89a19e7e8..fb70655041 100644
--- a/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/index/KtSymbolIndex.kt
+++ b/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/index/KtSymbolIndex.kt
@@ -10,7 +10,6 @@ import com.itsaky.androidide.lsp.kotlin.compiler.write
import com.itsaky.androidide.lsp.kotlin.utils.toVirtualFileOrNull
import com.itsaky.androidide.projects.FileManager
import com.itsaky.androidide.utils.DocumentUtils
-import io.sentry.Sentry
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -151,7 +150,6 @@ internal class KtSymbolIndex(
}
fun refreshSources() {
- Sentry.addBreadcrumb("KtSymbolIndex.refreshSources()")
indexingJob ?: startIndexing()
scanningJob?.cancel()
diff --git a/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/index/SourceFileIndexer.kt b/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/index/SourceFileIndexer.kt
index b03c205a92..c237066773 100644
--- a/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/index/SourceFileIndexer.kt
+++ b/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/index/SourceFileIndexer.kt
@@ -6,8 +6,6 @@ import com.itsaky.androidide.lsp.kotlin.compiler.read
import com.itsaky.androidide.lsp.kotlin.utils.toNioPathOrNull
import com.itsaky.androidide.progress.ICancelChecker
import com.itsaky.androidide.projects.FileManager
-import io.sentry.Attachment
-import io.sentry.Sentry
import org.appdevforall.codeonthego.indexing.jvm.JvmClassInfo
import org.appdevforall.codeonthego.indexing.jvm.JvmFieldInfo
import org.appdevforall.codeonthego.indexing.jvm.JvmFunctionInfo
@@ -134,23 +132,6 @@ private fun KaSession.analyzeDeclaration(filePath: String, dcl: KtDeclaration):
is KtTypeAlias -> analyzeTypeAlias(filePath, dcl)
else -> null
}
- }.onFailure { err ->
- Sentry.captureException(err) { scope ->
- scope.apply {
- setExtra("fpth", filePath)
- setExtra("dcl", dcl.name)
- setExtra("dcl.dbg", dcl.getDebugText())
- setExtra(
- "par.dbg",
- (dcl.parent as? KtElement)?.getDebugText() ?: dcl.parent?.toString() ?: "none"
- )
- if (err is KotlinExceptionWithAttachments) {
- err.attachments.forEach { attachment ->
- scope.addAttachment(Attachment(attachment.bytes, attachment.path))
- }
- }
- }
- }
}.getOrNull()
}
diff --git a/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/modules/AbstractKtModule.kt b/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/modules/AbstractKtModule.kt
index 9c1f603ef0..4b2acea21e 100644
--- a/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/modules/AbstractKtModule.kt
+++ b/lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/compiler/modules/AbstractKtModule.kt
@@ -1,6 +1,5 @@
package com.itsaky.androidide.lsp.kotlin.compiler.modules
-import io.sentry.Sentry
import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
import org.jetbrains.kotlin.analysis.api.KaPlatformInterface
import org.jetbrains.kotlin.analysis.api.platform.projectStructure.KaContentScopeProvider
@@ -26,7 +25,6 @@ internal abstract class AbstractKtModule(
_baseSearchScope = computeBaseContentScope()
_contentScope = KaContentScopeProvider.getInstance(project).getRefinedContentScope(this)
- Sentry.addBreadcrumb("createSearchScopes(mod=$this, base=${_baseSearchScope?.hashCode()}, content=${_contentScope?.hashCode()})")
}
/**
@@ -44,7 +42,6 @@ internal abstract class AbstractKtModule(
fun invalidateSearchScope() {
synchronized(searchScopeLock) {
- Sentry.addBreadcrumb("invalidateSearchScope(mod=$this)")
_baseSearchScope = null
_contentScope = null
}
diff --git a/resources/src/main/res/values-in-rID/strings.xml b/resources/src/main/res/values-in-rID/strings.xml
index 64c60e7ef1..6f74561290 100644
--- a/resources/src/main/res/values-in-rID/strings.xml
+++ b/resources/src/main/res/values-in-rID/strings.xml
@@ -585,7 +585,7 @@
Privasi
Privasi & analitik
- Code on the Go menggunakan Firebase Analytics dan Sentry untuk membantu kami meningkatkan aplikasi.\n\nFirebase Analytics mengumpulkan data penggunaan anonim untuk membantu kami memahami bagaimana aplikasi digunakan.\n\nSentry membantu kami melacak dan memperbaiki masalah.\n\nTidak ada informasi pribadi yang dikumpulkan atau dibagikan. Semua data diproses sesuai dengan kebijakan privasi kami.
+ Code on the Go menggunakan Firebase Analytics untuk membantu kami meningkatkan aplikasi.\n\nFirebase Analytics mengumpulkan data penggunaan anonim untuk membantu kami memahami bagaimana aplikasi digunakan.\n\nTidak ada informasi pribadi yang dikumpulkan atau dibagikan. Semua data diproses sesuai dengan kebijakan privasi kami.
Saya mengerti
Pelajari lebih lanjut
diff --git a/resources/src/main/res/values/strings.xml b/resources/src/main/res/values/strings.xml
index 32a90dfd87..28a05a486f 100644
--- a/resources/src/main/res/values/strings.xml
+++ b/resources/src/main/res/values/strings.xml
@@ -657,7 +657,7 @@
Privacy
Privacy & analytics
- Code on the Go uses Firebase Analytics and Sentry to help us improve the app.\n\nFirebase Analytics collects anonymous usage data to help us understand how the app is used. \n\nSentry helps us track and fix errors.\n\nNo personal information is collected or shared. All data is processed in accordance with our privacy policy.
+ Code on the Go uses Firebase Analytics to help us improve the app.\n\nFirebase Analytics collects anonymous usage data to help us understand how the app is used.\n\nNo personal information is collected or shared. All data is processed in accordance with our privacy policy.
I understand
Learn more