From 5d6c8339da0622cc980fa00eb0856a6faf2cbd05 Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Fri, 14 Jun 2024 19:44:31 +0530 Subject: [PATCH] fix: configure Dagger Hilt for DI --- build.gradle.kts | 1 + .../build-logic/plugins/build.gradle.kts | 1 + .../androidide/plugins/AndroidIDEPlugin.kt | 9 ++--- .../androidide/plugins/DIConfigPlugin.kt | 34 ++++++++++++++++++ .../androidide/plugins/util/pluginExts.kt | 29 +++++++++++++++ core/app/build.gradle.kts | 6 ++++ .../activities/editor/BaseEditorActivity.kt | 2 ++ .../editor/ProjectHandlerActivity.kt | 2 +- .../itsaky/androidide/app/IDEApplication.kt | 3 +- .../itsaky/androidide/di/ActivityModule.kt | 30 ++++++++++++++++ .../androidide/di/EditorActivityModule.kt | 30 ++++++++++++++++ .../services/builder/GradleBuildService.kt | 36 ++++++++++++------- gradle/libs.versions.toml | 9 +++++ 13 files changed, 174 insertions(+), 18 deletions(-) create mode 100644 composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/DIConfigPlugin.kt create mode 100644 composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/util/pluginExts.kt create mode 100644 core/app/src/main/java/com/itsaky/androidide/di/ActivityModule.kt create mode 100644 core/app/src/main/java/com/itsaky/androidide/di/EditorActivityModule.kt diff --git a/build.gradle.kts b/build.gradle.kts index 6303342a4..e75b71b5c 100755 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,6 +37,7 @@ plugins { alias(libs.plugins.gradle.publish) apply false alias(libs.plugins.protobuf) apply false alias(libs.plugins.benchmark) apply false + alias(libs.plugins.hilt) apply false } buildscript { diff --git a/composite-builds/build-logic/plugins/build.gradle.kts b/composite-builds/build-logic/plugins/build.gradle.kts index e887b8c71..1182b857d 100644 --- a/composite-builds/build-logic/plugins/build.gradle.kts +++ b/composite-builds/build-logic/plugins/build.gradle.kts @@ -37,6 +37,7 @@ dependencies { implementation(projects.buildLogic.propertiesParser) implementation("com.android.tools.build:gradle:${libs.versions.agp.asProvider().get()}") + implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${libs.versions.kotlin.asProvider().get()}") implementation(libs.maven.publish) implementation(libs.common.jkotlin) diff --git a/composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/AndroidIDEPlugin.kt b/composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/AndroidIDEPlugin.kt index 30aec9bb8..94af5fc23 100644 --- a/composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/AndroidIDEPlugin.kt +++ b/composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/AndroidIDEPlugin.kt @@ -19,6 +19,7 @@ package com.itsaky.androidide.plugins import com.android.build.gradle.BaseExtension import com.itsaky.androidide.build.config.isFDroidBuild +import com.itsaky.androidide.plugins.util.isAndroidModule import org.gradle.api.GradleException import org.gradle.api.Plugin import org.gradle.api.Project @@ -39,10 +40,10 @@ class AndroidIDEPlugin : Plugin { return@run } - val isAndroidModule = plugins.hasPlugin("com.android.application") || - plugins.hasPlugin("com.android.library") + // Apply dependency injection for all modules + plugins.apply(DIConfigPlugin::class.java) - if (isAndroidModule && !isFDroidBuild) { + if (this.isAndroidModule && !isFDroidBuild) { // setup signing configuration plugins.apply(SigningConfigPlugin::class.java) } @@ -57,7 +58,7 @@ class AndroidIDEPlugin : Plugin { } val taskName = when { - isAndroidModule -> "testDebugUnitTest" + this.isAndroidModule -> "testDebugUnitTest" else -> "test" } diff --git a/composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/DIConfigPlugin.kt b/composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/DIConfigPlugin.kt new file mode 100644 index 000000000..533d2235f --- /dev/null +++ b/composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/DIConfigPlugin.kt @@ -0,0 +1,34 @@ +/* + * 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.plugins + +import org.gradle.api.Plugin +import org.gradle.api.Project + +/** + * Configures dependency injection in a module. + * + * @author Akash Yadav + */ +class DIConfigPlugin : Plugin { + + override fun apply(target: Project) = target.run { + dependencies.add("implementation", "javax.inject:javax.inject:1") + Unit + } +} \ No newline at end of file diff --git a/composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/util/pluginExts.kt b/composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/util/pluginExts.kt new file mode 100644 index 000000000..0ba438f0e --- /dev/null +++ b/composite-builds/build-logic/plugins/src/main/java/com/itsaky/androidide/plugins/util/pluginExts.kt @@ -0,0 +1,29 @@ +/* + * 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.plugins.util + +import org.gradle.api.Project + +val Project.isAndroidModule: Boolean + get() = isAndroidApplication || isAndroidLibrary + +val Project.isAndroidApplication: Boolean + get() = plugins.hasPlugin("com.android.application") + +val Project.isAndroidLibrary: Boolean + get() = plugins.hasPlugin("com.android.library") \ No newline at end of file diff --git a/core/app/build.gradle.kts b/core/app/build.gradle.kts index ff00e1018..0631ea183 100755 --- a/core/app/build.gradle.kts +++ b/core/app/build.gradle.kts @@ -13,6 +13,7 @@ plugins { id("realm-android") id("androidx.navigation.safeargs.kotlin") id("com.itsaky.androidide.desugaring") + id("com.google.dagger.hilt.android") } apply { @@ -59,6 +60,8 @@ kapt { arguments { arg("eventBusIndex", "${BuildConfig.packageName}.events.AppEventsIndex") } + + correctErrorTypes = true } desugaring { @@ -77,6 +80,7 @@ dependencies { // Annotation processors kapt(libs.common.glide.ap) kapt(libs.google.auto.service) + kapt(libs.hilt.compiler) kapt(projects.annotation.processors) implementation(libs.common.editor) @@ -93,6 +97,8 @@ dependencies { implementation(libs.google.gson) implementation(libs.google.guava) + implementation(libs.hilt.android) + // Git implementation(libs.git.jgit) diff --git a/core/app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt b/core/app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt index a2138a485..72c4d0310 100644 --- a/core/app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt +++ b/core/app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt @@ -102,6 +102,7 @@ import com.itsaky.androidide.viewmodel.EditorViewModel import com.itsaky.androidide.xml.resources.ResourceTableRegistry import com.itsaky.androidide.xml.versions.ApiVersionsRegistry import com.itsaky.androidide.xml.widgets.WidgetTableRegistry +import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import org.greenrobot.eventbus.Subscribe @@ -118,6 +119,7 @@ import kotlin.math.roundToLong * @author Akash Yadav */ @Suppress("MemberVisibilityCanBePrivate") +@AndroidEntryPoint abstract class BaseEditorActivity : EdgeToEdgeIDEActivity(), TabLayout.OnTabSelectedListener, DiagnosticClickListener { diff --git a/core/app/src/main/java/com/itsaky/androidide/activities/editor/ProjectHandlerActivity.kt b/core/app/src/main/java/com/itsaky/androidide/activities/editor/ProjectHandlerActivity.kt index fec8eea10..b9e2bf5f1 100644 --- a/core/app/src/main/java/com/itsaky/androidide/activities/editor/ProjectHandlerActivity.kt +++ b/core/app/src/main/java/com/itsaky/androidide/activities/editor/ProjectHandlerActivity.kt @@ -454,7 +454,7 @@ abstract class ProjectHandlerActivity : BaseEditorActivity() { buildServiceConnection.onConnected = null editorViewModel.isBoundToBuildSerice = true - Lookup.getDefault().update(BuildService.KEY_BUILD_SERVICE, service) + service.setEventListener(mBuildEventListener) if (!service.isToolingServerStarted()) { diff --git a/core/app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt b/core/app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt index 1039b9701..536c8c410 100755 --- a/core/app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt +++ b/core/app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt @@ -58,6 +58,7 @@ import com.itsaky.androidide.utils.VMUtils import com.itsaky.androidide.utils.flashError import com.termux.app.TermuxApplication import com.termux.shared.reflection.ReflectionUtils +import dagger.hilt.android.HiltAndroidApp import io.github.rosemoe.sora.widget.schemes.EditorColorScheme import io.realm.Realm import kotlinx.coroutines.DelicateCoroutinesApi @@ -71,7 +72,7 @@ import java.lang.Thread.UncaughtExceptionHandler import java.time.Duration import kotlin.system.exitProcess - +@HiltAndroidApp class IDEApplication : TermuxApplication() { private var uncaughtExceptionHandler: UncaughtExceptionHandler? = null diff --git a/core/app/src/main/java/com/itsaky/androidide/di/ActivityModule.kt b/core/app/src/main/java/com/itsaky/androidide/di/ActivityModule.kt new file mode 100644 index 000000000..1d52fb9a7 --- /dev/null +++ b/core/app/src/main/java/com/itsaky/androidide/di/ActivityModule.kt @@ -0,0 +1,30 @@ +/* + * 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.di + +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ActivityComponent + +/** + * @author Akash Yadav + */ +@Module +@InstallIn(ActivityComponent::class) +abstract class ActivityModule { +} \ No newline at end of file diff --git a/core/app/src/main/java/com/itsaky/androidide/di/EditorActivityModule.kt b/core/app/src/main/java/com/itsaky/androidide/di/EditorActivityModule.kt new file mode 100644 index 000000000..c70ccc0ae --- /dev/null +++ b/core/app/src/main/java/com/itsaky/androidide/di/EditorActivityModule.kt @@ -0,0 +1,30 @@ +/* + * 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.di + +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ActivityComponent + +/** + * @author Akash Yadav + */ +@Module +@InstallIn(ActivityComponent::class) +abstract class EditorActivityModule { +} \ No newline at end of file diff --git a/core/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.kt b/core/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.kt index 827be7e6d..561d7229f 100644 --- a/core/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.kt +++ b/core/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.kt @@ -59,6 +59,7 @@ import com.itsaky.androidide.tooling.api.models.ToolingServerMetadata import com.itsaky.androidide.tooling.events.ProgressEvent import com.itsaky.androidide.utils.Environment import com.termux.shared.termux.shell.command.environment.TermuxShellEnvironment +import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -78,6 +79,7 @@ import java.util.concurrent.TimeUnit * * @author Akash Yadav */ +@AndroidEntryPoint class GradleBuildService : Service(), BuildService, IToolingApiClient, ToolingServerRunner.Observer { @@ -100,7 +102,8 @@ class GradleBuildService : Service(), BuildService, IToolingApiClient, private var eventListener: EventListener? = null private val buildServiceScope = CoroutineScope( - Dispatchers.Default + CoroutineName("GradleBuildService")) + Dispatchers.Default + CoroutineName("GradleBuildService") + ) private val isGradleWrapperAvailable: Boolean get() { @@ -122,7 +125,6 @@ class GradleBuildService : Service(), BuildService, IToolingApiClient, } companion object { - private val log = LoggerFactory.getLogger(GradleBuildService::class.java) private val NOTIFICATION_ID = R.string.app_name private val SERVER_System_err = LoggerFactory.getLogger("ToolingApiErrorStream") @@ -138,8 +140,10 @@ class GradleBuildService : Service(), BuildService, IToolingApiClient, return isToolingServerStarted && server != null } - private fun showNotification(message: String, - @Suppress("SameParameterValue") isProgress: Boolean) { + private fun showNotification( + message: String, + @Suppress("SameParameterValue") isProgress: Boolean + ) { log.info("Showing notification to user...") createNotificationChannels() startForeground(NOTIFICATION_ID, buildNotification(message, isProgress)) @@ -149,7 +153,8 @@ class GradleBuildService : Service(), BuildService, IToolingApiClient, val buildNotificationChannel = NotificationChannel( BaseApplication.NOTIFICATION_GRADLE_BUILD_SERVICE, getString(string.title_gradle_service_notification_channel), - NotificationManager.IMPORTANCE_LOW) + NotificationManager.IMPORTANCE_LOW + ) NotificationManagerCompat.from(this) .createNotificationChannel(buildNotificationChannel) } @@ -315,7 +320,8 @@ class GradleBuildService : Service(), BuildService, IToolingApiClient, override fun checkGradleWrapperAvailability(): CompletableFuture { return if (isGradleWrapperAvailable) CompletableFuture.completedFuture( - GradleWrapperCheckResult(true)) else installWrapper() + GradleWrapperCheckResult(true) + ) else installWrapper() } internal fun setServerListener(listener: OnServerStartListener?) { @@ -335,8 +341,10 @@ class GradleBuildService : Service(), BuildService, IToolingApiClient, private fun doInstallWrapper(): GradleWrapperCheckResult { val extracted = File(Environment.TMP_DIR, "gradle-wrapper.zip") - if (!ResourceUtils.copyFileFromAssets(ToolsManager.getCommonAsset("gradle-wrapper.zip"), - extracted.absolutePath) + if (!ResourceUtils.copyFileFromAssets( + ToolsManager.getCommonAsset("gradle-wrapper.zip"), + extracted.absolutePath + ) ) { log.error("Unable to extract gradle-plugin.zip from IDE resources.") return GradleWrapperCheckResult(false) @@ -358,8 +366,10 @@ class GradleBuildService : Service(), BuildService, IToolingApiClient, } private fun doUpdateNotification(message: String, isProgress: Boolean) { - (getSystemService(NOTIFICATION_SERVICE) as NotificationManager).notify(NOTIFICATION_ID, - buildNotification(message, isProgress)) + (getSystemService(NOTIFICATION_SERVICE) as NotificationManager).notify( + NOTIFICATION_ID, + buildNotification(message, isProgress) + ) } override fun metadata(): CompletableFuture { @@ -368,7 +378,8 @@ class GradleBuildService : Service(), BuildService, IToolingApiClient, } override fun initializeProject( - params: InitializeProjectParams): CompletableFuture { + params: InitializeProjectParams + ): CompletableFuture { checkServerStarted() Objects.requireNonNull(params) return performBuildTasks(server!!.initialize(params)) @@ -481,7 +492,8 @@ class GradleBuildService : Service(), BuildService, IToolingApiClient, } outputReaderJob = buildServiceScope.launch( - Dispatchers.IO + CoroutineName("ToolingServerErrorReader")) { + Dispatchers.IO + CoroutineName("ToolingServerErrorReader") + ) { val reader = input.bufferedReader() try { reader.forEachLine { line -> diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2f73ff361..af5bc65c2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,6 +21,7 @@ logback = "1.5.3" realm = "10.18.0" benchmark = "1.2.4" benchmark-junit4 = "1.2.4" +hilt = "2.51.1" [libraries] @@ -75,6 +76,13 @@ common-hiddenApiBypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass common-termuxAmLib = { module = "com.termux:termux-am-library", version = "v2.0.0" } common-charts = { module = "com.github.AppDevNext:AndroidChart", version = "3.1.0.21" } +# Dependency Injection +## DO NOT REMOVE +## Accessed programmatically in DIConfigPlugin +## Update DIConfigPlugin if renamed +hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } +hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" } + # AndroidX androidx-annotation = { module = "androidx.annotation:annotation", version = "1.7.1" } androidx-appcompat = { module = "androidx.appcompat:appcompat", version = "1.6.1" } @@ -179,3 +187,4 @@ maven-publish = { id = "com.vanniktech.maven.publish.base", version.ref = "maven gradle-publish = { id = "com.gradle.plugin-publish", version = "1.2.1" } protobuf = { id = "com.google.protobuf", version = "0.9.4" } benchmark = { id = "androidx.benchmark", version.ref = "benchmark" } +hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } \ No newline at end of file