Repository: square/leakcanary
File: leakcanary-android-core/src/main/java/leakcanary/internal/InternalLeakCanary.kt (Kotlin)

Code before:
    }
    registerResumedActivityListener(application)
    addDynamicShortcut(application)

    disableDumpHeapInTests()
  }

  private fun checkAllowInNonDebuggableBuild() {
    if (AppWatcher.isDebuggableBuild) {
      return
    }

    if (application.resources.getBoolean(R.bool.leak_canary_allow_in_non_debuggable_build)) {
      // AppWatcher is disabled by default for non-debuggable builds, but we have a developer opt-in.
      AppWatcher.config = AppWatcher.config.copy(enabled = true)
    } else {
      throw Error("""
        LeakCanary in non-debuggable build
        
        LeakCanary should only be used in debug builds, but this APK is not marked as debuggable.
        Please follow the instructions on the "Getting started" page to only include LeakCanary in
        debug builds: https://square.github.io/leakcanary/getting_started/
        
        If you're sure you want to include LeakCanary in a non-debuggable build, you can disable this
        check by overriding the bool/leak_canary_allow_in_non_debuggable_build resource and setting
        the value to 'true'.
      """.trimIndent())
    }
  }

  private fun registerResumedActivityListener(application: Application) {
    application.registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks by noOpDelegate() {
      override fun onActivityResumed(activity: Activity) {
        resumedActivity = activity
      }

      override fun onActivityPaused(activity: Activity) {
        if (resumedActivity === activity) {
          resumedActivity = null
        }
      }
    })
  }

  private fun disableDumpHeapInTests() {
    // This is called before Application.onCreate(), so if the class is loaded through a secondary
    // dex it might not be available yet.
    Handler().post {
      if (isRunningTests) {
        SharkLog.d { "$testClassName detected in classpath, app is running tests => disabling heap dumping & analysis" }
        LeakCanary.config = LeakCanary.config.copy(dumpHeap = false)

Review comment (suggestion):
I think it would be better to add a corresponding section in the [Code recipes](https://square.github.io/leakcanary/recipes/) and have the error message point to that page with an anchor to a detailed description with xml snippet to copy&paste. Source code of those docs is located in `/leakcanary/docs/recipes.md`

Code after:
        configProvider
    )
    application.registerVisibilityListener { applicationVisible ->
      this.applicationVisible = applicationVisible
      heapDumpTrigger.onApplicationVisibilityChanged(applicationVisible)
    }
    registerResumedActivityListener(application)
    addDynamicShortcut(application)

    disableDumpHeapInTests()
  }

  private fun checkRunningInDebuggableBuild() {
    if (isDebuggableBuild) {
      return
    }

    if (application.resources.getBoolean(R.bool.leak_canary_allow_in_non_debuggable_build)) {
      // AppWatcher is disabled by default for non-debuggable builds, but we have a developer opt-in.
      AppWatcher.config = AppWatcher.config.copy(enabled = true)
    } else {
      throw Error("""
        LeakCanary in non-debuggable build
        
        LeakCanary should only be used in debug builds, but this APK is not debuggable.
        Please follow the instructions on the "Getting started" page to only include LeakCanary in
        debug builds: https://square.github.io/leakcanary/getting_started/
        
        If you're sure you want to include LeakCanary in a non-debuggable build, follow the 
        instructions here: https://square.github.io/leakcanary/recipes/#leakcanary-in-release-builds
      """.trimIndent())
    }
  }

  private fun registerResumedActivityListener(application: Application) {
    application.registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks by noOpDelegate() {
      override fun onActivityResumed(activity: Activity) {
        resumedActivity = activity
      }

      override fun onActivityPaused(activity: Activity) {
        if (resumedActivity === activity) {
          resumedActivity = null
        }
      }
    })
  }

  private fun disableDumpHeapInTests() {
    // This is called before Application.onCreate(), so if the class is loaded through a secondary
    // dex it might not be available yet.