diff --git a/app/build.gradle b/app/build.gradle
index 276ca88e9..47239dc96 100755
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -14,6 +14,12 @@ android {
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
+
+ javaCompileOptions {
+ annotationProcessorOptions {
+ arguments = [ eventBusIndex : 'com.itsaky.androidide.events.AndroidIDEEventBusIndex' ]
+ }
+ }
}
compileOptions {
@@ -87,6 +93,7 @@ dependencies {
// Annotation processors
annotationProcessor common.glide_ap
+ annotationProcessor common.eventbus_ap
implementation common.editor
implementation common.utilcode
diff --git a/app/src/main/java/com/itsaky/androidide/EditorActivity.java b/app/src/main/java/com/itsaky/androidide/EditorActivity.java
index 1053d7559..103aef579 100755
--- a/app/src/main/java/com/itsaky/androidide/EditorActivity.java
+++ b/app/src/main/java/com/itsaky/androidide/EditorActivity.java
@@ -87,7 +87,6 @@ import com.itsaky.androidide.fragments.SimpleOutputFragment;
import com.itsaky.androidide.fragments.sheets.ProgressSheet;
import com.itsaky.androidide.fragments.sheets.TextSheetFragment;
import com.itsaky.androidide.handlers.EditorEventListener;
-import com.itsaky.androidide.handlers.FileTreeActionHandler;
import com.itsaky.androidide.interfaces.DiagnosticClickListener;
import com.itsaky.androidide.interfaces.EditorActivityProvider;
import com.itsaky.androidide.lsp.IDELanguageClientImpl;
@@ -102,7 +101,6 @@ import com.itsaky.androidide.models.LogLine;
import com.itsaky.androidide.models.Range;
import com.itsaky.androidide.models.SaveResult;
import com.itsaky.androidide.models.SearchResult;
-import com.itsaky.androidide.projects.FileManager;
import com.itsaky.androidide.projects.ProjectManager;
import com.itsaky.androidide.projects.api.Project;
import com.itsaky.androidide.services.GradleBuildService;
@@ -110,12 +108,10 @@ import com.itsaky.androidide.services.LogReceiver;
import com.itsaky.androidide.shell.ShellServer;
import com.itsaky.androidide.tooling.api.messages.result.SimpleVariantData;
import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult;
-import com.itsaky.androidide.utils.BootClasspathProvider;
import com.itsaky.androidide.utils.CharSequenceInputStream;
import com.itsaky.androidide.utils.DialogUtils;
import com.itsaky.androidide.utils.EditorActivityActions;
import com.itsaky.androidide.utils.EditorBottomSheetBehavior;
-import com.itsaky.androidide.utils.Environment;
import com.itsaky.androidide.utils.ILogger;
import com.itsaky.androidide.utils.LSPUtils;
import com.itsaky.androidide.utils.RecursiveFileSearcher;
@@ -164,7 +160,6 @@ public class EditorActivity extends StudioActivity
private static final int ACTION_ID_ALL = 102;
private static final ILogger LOG = ILogger.newInstance("EditorActivity");
private final EditorEventListener mBuildEventListener = new EditorEventListener();
- private final FileTreeActionHandler mFileActionsHandler = new FileTreeActionHandler();
private ActivityEditorBinding mBinding;
private LayoutDiagnosticInfoBinding mDiagnosticInfoBinding;
private EditorBottomSheetTabAdapter bottomSheetTabAdapter;
@@ -1127,27 +1122,6 @@ public class EditorActivity extends StudioActivity
}
}
- @Override
- protected void onStart() {
- super.onStart();
-
- // Make sure we list and store the bootstrap classes
- CompletableFuture.runAsync(
- () ->
- BootClasspathProvider.update(
- Collections.singleton(Environment.ANDROID_JAR.getAbsolutePath())));
-
- mFileActionsHandler.register();
- FileManager.INSTANCE.register();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- mFileActionsHandler.unregister();
- FileManager.INSTANCE.unregister();
- }
-
@Override
protected void onDestroy() {
closeProject(false);
diff --git a/app/src/main/java/com/itsaky/androidide/app/StudioApp.java b/app/src/main/java/com/itsaky/androidide/app/StudioApp.java
index 5d4ef0ca8..3293802fa 100755
--- a/app/src/main/java/com/itsaky/androidide/app/StudioApp.java
+++ b/app/src/main/java/com/itsaky/androidide/app/StudioApp.java
@@ -24,6 +24,7 @@ import androidx.annotation.NonNull;
import com.blankj.utilcode.util.ThrowableUtils;
import com.itsaky.androidide.CrashHandlerActivity;
import com.itsaky.androidide.R;
+import com.itsaky.androidide.eventbus.events.Event;
import com.itsaky.androidide.projects.ProjectResourceTable;
import com.itsaky.androidide.utils.ILogger;
import com.itsaky.apiinfo.ApiInfo;
@@ -38,6 +39,8 @@ import com.itsaky.androidide.lsp.xml.XMLLanguageServer;
import com.itsaky.sdk.SDKInfo;
import com.itsaky.widgets.WidgetInfo;
+import org.greenrobot.eventbus.EventBus;
+
import java.io.File;
import java.util.Objects;
import java.util.Set;
@@ -62,6 +65,7 @@ public class StudioApp extends BaseApplication {
this.uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this::handleCrash);
super.onCreate();
+
getApiInformation();
}
diff --git a/app/src/main/java/com/itsaky/androidide/handlers/EditorActivityLifecyclerObserver.kt b/app/src/main/java/com/itsaky/androidide/handlers/EditorActivityLifecyclerObserver.kt
new file mode 100644
index 000000000..87035f88b
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/handlers/EditorActivityLifecyclerObserver.kt
@@ -0,0 +1,83 @@
+/*
+ * 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 androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import com.itsaky.androidide.EditorActivity
+import com.itsaky.androidide.eventbus.events.Event
+import com.itsaky.androidide.eventbus.events.EventReceiver
+import com.itsaky.androidide.eventbus.events.editor.OnCreateEvent
+import com.itsaky.androidide.eventbus.events.editor.OnDestroyEvent
+import com.itsaky.androidide.eventbus.events.editor.OnPauseEvent
+import com.itsaky.androidide.eventbus.events.editor.OnResumeEvent
+import com.itsaky.androidide.eventbus.events.editor.OnStartEvent
+import com.itsaky.androidide.eventbus.events.editor.OnStopEvent
+import com.itsaky.androidide.projects.FileManager
+import com.itsaky.androidide.projects.ProjectManager
+import com.itsaky.androidide.utils.BootClasspathProvider
+import java.util.concurrent.*
+
+/**
+ * Observes lifecycle events if [com.itsaky.androidide.EditorActivity].
+ *
+ * @author Akash Yadav
+ */
+class EditorActivityLifecyclerObserver : DefaultLifecycleObserver {
+
+ private val fileActionsHandler = FileTreeActionHandler()
+
+ override fun onCreate(owner: LifecycleOwner) {
+ dispatchEvent(OnCreateEvent())
+ }
+
+ override fun onStart(owner: LifecycleOwner) {
+ CompletableFuture.runAsync(BootClasspathProvider::init)
+ register(fileActionsHandler, FileManager, ProjectManager)
+
+ dispatchEvent(OnStartEvent())
+ }
+
+ override fun onResume(owner: LifecycleOwner) {
+ dispatchEvent(OnResumeEvent())
+ }
+
+ override fun onPause(owner: LifecycleOwner) {
+ dispatchEvent(OnPauseEvent())
+ }
+
+ override fun onStop(owner: LifecycleOwner) {
+ unregister(fileActionsHandler, FileManager, ProjectManager)
+
+ dispatchEvent(OnStopEvent())
+ }
+
+ override fun onDestroy(owner: LifecycleOwner) {
+ dispatchEvent(OnDestroyEvent())
+ }
+
+ private fun register(vararg receivers: EventReceiver) {
+ receivers.forEach { it.register() }
+ }
+
+ private fun unregister(vararg receivers: EventReceiver) {
+ receivers.forEach { it.unregister() }
+ }
+
+ private fun dispatchEvent(event: Event) {}
+}
diff --git a/build-tools/eventbus-events/src/main/java/com/itsaky/androidide/eventbus/events/editor/ActivityLifecycleEvents.kt b/build-tools/eventbus-events/src/main/java/com/itsaky/androidide/eventbus/events/editor/ActivityLifecycleEvents.kt
new file mode 100644
index 000000000..f1e57a8a8
--- /dev/null
+++ b/build-tools/eventbus-events/src/main/java/com/itsaky/androidide/eventbus/events/editor/ActivityLifecycleEvents.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.eventbus.events.editor
+
+import com.itsaky.androidide.eventbus.events.Event
+
+abstract class EditorActivityLifecycleEvent : Event()
+
+/**
+ * Dispatched just after `EditorActivity`'s `onCreate` method.
+ *
+ * @author Akash Yadav
+ */
+class OnCreateEvent : EditorActivityLifecycleEvent()
+
+/**
+ * Dispatched just after `EditorActivity`'s `onStart` method.
+ *
+ * @author Akash Yadav
+ */
+class OnStartEvent : EditorActivityLifecycleEvent()
+
+/**
+ * Dispatched just after `EditorActivity`'s `onResume` method.
+ *
+ * @author Akash Yadav
+ */
+class OnResumeEvent : EditorActivityLifecycleEvent()
+
+/**
+ * Dispatched just before `EditorActivity`'s `onPause` method.
+ *
+ * @author Akash Yadav
+ */
+class OnPauseEvent : EditorActivityLifecycleEvent()
+
+/**
+ * Dispatched just before `EditorActivity`'s `onStop` method.
+ *
+ * @author Akash Yadav
+ */
+class OnStopEvent : EditorActivityLifecycleEvent()
+
+/**
+ * Dispatched just before `EditorActivity`'s `onDestroy` method.
+ *
+ * @author Akash Yadav
+ */
+class OnDestroyEvent : EditorActivityLifecycleEvent()
diff --git a/build-tools/eventbus/src/main/java/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java b/build-tools/eventbus/src/main/java/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java
index 9fc65f6ff..02da55336 100644
--- a/build-tools/eventbus/src/main/java/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java
+++ b/build-tools/eventbus/src/main/java/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java
@@ -15,9 +15,7 @@
*/
package org.greenrobot.eventbus.meta;
-/**
- * Interface for generated indexes.
- */
+/** Interface for generated indexes. */
public interface SubscriberInfoIndex {
- SubscriberInfo getSubscriberInfo(Class> subscriberClass);
+ SubscriberInfo getSubscriberInfo(Class> subscriberClass);
}
diff --git a/build.gradle b/build.gradle
index ce715a3ee..c2a240406 100755
--- a/build.gradle
+++ b/build.gradle
@@ -47,60 +47,69 @@ subprojects {
project.afterEvaluate {
tasks.register ("checkTranslations", task -> {
- def php = new File ("/usr/bin/php")
- if (!php.exists ()) {
- project.logger.lifecycle ("'${php.absolutePath}' not found. Skipping translation check.")
- return
- }
-
- def resDir = project.file ("src/main/res")
- def strings = new File (resDir, "values/strings.xml")
- def reportDir = new File (project.rootProject.buildDir, "translation-reports")
- reportDir.delete ()
-
- if (resDir.exists () && strings.exists ()) {
- def translationDirs = resDir.listFiles ((FileFilter) (file -> {
- return file.isDirectory () && file.getName ().startsWith ("values-")
- }))
- for (def dir : translationDirs) {
- final var translation = new File (dir, "strings.xml")
- if (translation.exists ()) {
- def out = new File (reportDir, "${project.path.replace (':', '/')}/${dir.name}.txt")
- if (!out.parentFile.exists ()) {
- out.parentFile.mkdirs ()
- }
-
- if (out.exists ()) {
- out.delete ()
- }
- out.createNewFile ()
-
- def result = exec {
- ignoreExitValue true
- standardOutput new FileOutputStream (out)
- commandLine "${php.absolutePath}",
- "${project.rootProject.file (".tools/strings-check.php")}",
- "${strings.absolutePath}",
- "${translation.absolutePath}"
- }
-
- if (result.getExitValue () == 0) {
- out.delete ()
- } else {
- project.logger.lifecycle ("Translation report for '${project.path}/${dir.name}' is written to '${out.absolutePath}'")
- }
-
- } else {
- project.logger.info ("No translation file specifed for '${dir.name}'. Skipping..")
- }
- }
- } else {
- project.logger.info ("Default strings.xml file does not exist for project '${project.name}'")
+ doLast {
+ checkTranslations (project)
}
})
}
}
+private void checkTranslations (def project) {
+ def php = new File ("/usr/bin/php")
+ if (!php.exists ()) {
+ project.logger.lifecycle ("'${php.absolutePath}' not found. Skipping translation check.")
+ return
+ }
+
+ def resDir = project.file ("src/main/res")
+ def strings = new File (resDir, "values/strings.xml")
+ def reportDir = new File (project.rootProject.buildDir, "translation-reports")
+ reportDir.delete ()
+
+ if (!resDir.exists () || !strings.exists ()) {
+ project.logger.info ("Default strings.xml file does not exist for project '${project.name}'")
+ return
+ }
+
+ def translationDirs = resDir.listFiles ((FileFilter) (file -> {
+ return file.isDirectory () && file.getName ().startsWith ("values-")
+ }))
+
+ for (def dir : translationDirs) {
+ final var translation = new File (dir, "strings.xml")
+ if (!translation.exists ()) {
+ project.logger.info ("No translation file specifed for '${dir.name}'. Skipping..")
+ return
+ }
+
+ def out = new File (reportDir, "${project.path.replace (':', '/')}/${dir.name}.txt")
+ if (!out.parentFile.exists ()) {
+ out.parentFile.mkdirs ()
+ }
+
+ if (out.exists ()) {
+ out.delete ()
+ }
+
+ out.createNewFile ()
+
+ def result = exec {
+ ignoreExitValue true
+ standardOutput new FileOutputStream (out)
+ commandLine "${php.absolutePath}",
+ "${project.rootProject.file (".tools/strings-check.php")}",
+ "${strings.absolutePath}",
+ "${translation.absolutePath}"
+ }
+
+ if (result.getExitValue () == 0) {
+ out.delete ()
+ } else {
+ project.logger.lifecycle ("Translation report for '${project.path}/${dir.name}' is written to '${out.absolutePath}'")
+ }
+ }
+}
+
allprojects {
tasks.withType (org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
diff --git a/common/src/main/java/com/itsaky/androidide/utils/BootClasspathProvider.java b/common/src/main/java/com/itsaky/androidide/utils/BootClasspathProvider.java
index 76a5b5487..9e0c57bd3 100644
--- a/common/src/main/java/com/itsaky/androidide/utils/BootClasspathProvider.java
+++ b/common/src/main/java/com/itsaky/androidide/utils/BootClasspathProvider.java
@@ -35,6 +35,11 @@ public class BootClasspathProvider {
private static final Map bootClasspathClasses = new ConcurrentHashMap<>();
private static final ILogger LOG = ILogger.newInstance("BootClassProvider");
+ /** Initializes the classpath provider with the default boot classpath. */
+ public static synchronized void init() {
+ update(Collections.singleton(Environment.ANDROID_JAR.getAbsolutePath()));
+ }
+
/**
* Updates the boot classpath cache. If a classpath is already indexed, it is skipped.
*
diff --git a/dependencies.gradle b/dependencies.gradle
index dba289885..a0790b856 100755
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -23,7 +23,8 @@ ext {
lang3 : 'org.apache.commons:commons-lang3:3.12.0',
io : 'commons-io:commons-io:2.11.0',
kotlin : 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0',
- jkotlin : 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
+ jkotlin : 'org.jetbrains.kotlin:kotlin-stdlib-jdk8',
+ eventbus_ap: 'org.greenrobot:eventbus-annotation-processor:3.3.1'
]
androidx = [
diff --git a/tests/test-home/.androidide/init/model.jar b/tests/test-home/.androidide/init/model.jar
index 4dc5cb38b..03b2b7f3b 100644
Binary files a/tests/test-home/.androidide/init/model.jar and b/tests/test-home/.androidide/init/model.jar differ