diff --git a/build-tools/framework-stubs/.gitignore b/build-tools/framework-stubs/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/build-tools/framework-stubs/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/build-tools/framework-stubs/build.gradle b/build-tools/framework-stubs/build.gradle
new file mode 100644
index 000000000..756235ed3
--- /dev/null
+++ b/build-tools/framework-stubs/build.gradle
@@ -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 .
+ */
+
+plugins {
+ id 'java-library'
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+}
+
+dependencies {
+ compileOnlyApi files('libs/android.jar')
+}
\ No newline at end of file
diff --git a/build-tools/framework-stubs/libs/android.jar b/build-tools/framework-stubs/libs/android.jar
new file mode 100644
index 000000000..34f5d75c4
Binary files /dev/null and b/build-tools/framework-stubs/libs/android.jar differ
diff --git a/build-tools/logger/.gitignore b/build-tools/logger/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/build-tools/logger/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/build-tools/logger/build.gradle b/build-tools/logger/build.gradle
new file mode 100644
index 000000000..b98f0d4d8
--- /dev/null
+++ b/build-tools/logger/build.gradle
@@ -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 .
+ */
+
+plugins {
+ id 'java-library'
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+}
+
+dependencies {
+ compileOnly project(path: ':build-tools:framework-stubs')
+}
\ No newline at end of file
diff --git a/build-tools/logger/src/main/java/com/itsaky/androidide/utils/LogUtils.java b/build-tools/logger/src/main/java/com/itsaky/androidide/utils/LogUtils.java
new file mode 100644
index 000000000..8835042c5
--- /dev/null
+++ b/build-tools/logger/src/main/java/com/itsaky/androidide/utils/LogUtils.java
@@ -0,0 +1,101 @@
+/*
+ * 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.utils;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * Utility class for {@link Logger}.
+ *
+ * @author Akash Yadav
+ */
+class LogUtils {
+ private static final String LINE_SEP = System.getProperty("line.separator");
+
+ public static String getFullStackTrace(Throwable throwable) {
+ final List throwableList = new ArrayList<>();
+ while (throwable != null && !throwableList.contains(throwable)) {
+ throwableList.add(throwable);
+ throwable = throwable.getCause();
+ }
+ final int size = throwableList.size();
+ final List frames = new ArrayList<>();
+ List nextTrace = getStackFrameList(throwableList.get(size - 1));
+ for (int i = size; --i >= 0; ) {
+ final List trace = nextTrace;
+ if (i != 0) {
+ nextTrace = getStackFrameList(throwableList.get(i - 1));
+ removeCommonFrames(trace, nextTrace);
+ }
+ if (i == size - 1) {
+ frames.add(throwableList.get(i).toString());
+ } else {
+ frames.add(" Caused by: " + throwableList.get(i).toString());
+ }
+ frames.addAll(trace);
+ }
+ StringBuilder sb = new StringBuilder();
+ for (final String element : frames) {
+ sb.append(element).append(LINE_SEP);
+ }
+ return sb.toString();
+ }
+
+ private static List getStackFrameList(final Throwable throwable) {
+ final StringWriter sw = new StringWriter();
+ final PrintWriter pw = new PrintWriter(sw, true);
+ throwable.printStackTrace(pw);
+ final String stackTrace = sw.toString();
+ final StringTokenizer frames = new StringTokenizer(stackTrace, LINE_SEP);
+ final List list = new ArrayList<>();
+ boolean traceStarted = false;
+ while (frames.hasMoreTokens()) {
+ final String token = frames.nextToken();
+ // Determine if the line starts with at
+ final int at = token.indexOf("at");
+ if (at != -1 && token.substring(0, at).trim().isEmpty()) {
+ traceStarted = true;
+ list.add(token);
+ } else if (traceStarted) {
+ break;
+ }
+ }
+ return list;
+ }
+
+ private static void removeCommonFrames(
+ final List causeFrames, final List wrapperFrames) {
+ int causeFrameIndex = causeFrames.size() - 1;
+ int wrapperFrameIndex = wrapperFrames.size() - 1;
+ while (causeFrameIndex >= 0 && wrapperFrameIndex >= 0) {
+ // Remove the frame from the cause trace if it is the same
+ // as in the wrapper trace
+ final String causeFrame = causeFrames.get(causeFrameIndex);
+ final String wrapperFrame = wrapperFrames.get(wrapperFrameIndex);
+ if (causeFrame.equals(wrapperFrame)) {
+ causeFrames.remove(causeFrameIndex);
+ }
+ causeFrameIndex--;
+ wrapperFrameIndex--;
+ }
+ }
+}
diff --git a/common/src/main/java/com/itsaky/androidide/utils/Logger.java b/build-tools/logger/src/main/java/com/itsaky/androidide/utils/Logger.java
old mode 100755
new mode 100644
similarity index 87%
rename from common/src/main/java/com/itsaky/androidide/utils/Logger.java
rename to build-tools/logger/src/main/java/com/itsaky/androidide/utils/Logger.java
index 9ba5676a8..7f456aff4
--- a/common/src/main/java/com/itsaky/androidide/utils/Logger.java
+++ b/build-tools/logger/src/main/java/com/itsaky/androidide/utils/Logger.java
@@ -1,3 +1,20 @@
+/*
+ * 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 .
+ */
+
/*
* This file is part of AndroidIDE.
*
@@ -19,12 +36,6 @@ package com.itsaky.androidide.utils;
import android.util.Log;
-import androidx.annotation.NonNull;
-
-import com.blankj.utilcode.util.ThrowableUtils;
-
-import org.jetbrains.annotations.Contract;
-
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -57,8 +68,6 @@ public class Logger {
return instance == null ? instance = createInstance("AndroidIDE") : instance;
}
- @NonNull
- @Contract("_ -> new")
private static Logger createInstance(String tag) {
return new Logger(tag);
}
@@ -71,14 +80,10 @@ public class Logger {
logListeners.remove(Objects.requireNonNull(listener));
}
- @NonNull
- @Contract("_ -> new")
public static Logger newInstance(String tag) {
return createInstance(tag);
}
- @NonNull
- @Contract(pure = true)
public static String priorityText(int priority) {
switch (priority) {
case DEBUG:
@@ -96,8 +101,6 @@ public class Logger {
}
}
- @NonNull
- @Contract(pure = true)
public static String priorityChar(int priority) {
switch (priority) {
case INFO:
@@ -120,7 +123,6 @@ public class Logger {
return this;
}
- @NonNull
protected String generateMessage(Object... messages) {
StringBuilder sb = new StringBuilder();
if (messages == null) {
@@ -130,9 +132,7 @@ public class Logger {
for (Object msg : messages) {
sb.append(msg instanceof Throwable ? "\n" : MSG_SEPARATOR);
sb.append(
- msg instanceof Throwable
- ? ThrowableUtils.getFullStackTrace(((Throwable) msg))
- : msg);
+ msg instanceof Throwable ? LogUtils.getFullStackTrace(((Throwable) msg)) : msg);
sb.append(msg instanceof Throwable ? "\n" : MSG_SEPARATOR);
}
diff --git a/common/build.gradle b/common/build.gradle
index bfcdc99ac..2dfffc1dc 100755
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -39,4 +39,6 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
api androidx.multidex
+
+ api project (path: ':build-tools:logger')
}
diff --git a/settings.gradle b/settings.gradle
index 4f8056e50..91e2c59f6 100755
--- a/settings.gradle
+++ b/settings.gradle
@@ -16,7 +16,9 @@ include ':lsp:xml'
include ':lsp:testing'
include ':build-tools'
-include ':build-tools:javac'
+include ':build-tools:framework-stubs'
include ':build-tools:google-java-format'
+include ':build-tools:javac'
+include ':build-tools:logger'
include ':build-tools:tooling-api'
include ':build-tools:tooling-api-iml'