Skip to content

Commit 12ab4b0

Browse files
committed
fix: add base files for the indexing API
1 parent 87ced38 commit 12ab4b0

45 files changed

Lines changed: 3627 additions & 70 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/build.gradle.kts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ plugins {
1212
id("kotlin-android")
1313
id("kotlin-kapt")
1414
id("kotlin-parcelize")
15+
id("realm-android")
1516
id("androidx.navigation.safeargs.kotlin")
1617
id("com.itsaky.androidide.desugaring")
1718
}
@@ -51,7 +52,11 @@ android {
5152
}
5253
}
5354

54-
kapt { arguments { arg("eventBusIndex", "${BuildConfig.packageName}.events.AppEventsIndex") } }
55+
kapt {
56+
arguments {
57+
arg("eventBusIndex", "${BuildConfig.packageName}.events.AppEventsIndex")
58+
}
59+
}
5560

5661
desugaring {
5762
replacements {
@@ -142,6 +147,7 @@ dependencies {
142147
implementation(projects.gradlePluginConfig)
143148
implementation(projects.idestats)
144149
implementation(projects.subprojects.aaptcompiler)
150+
implementation(projects.subprojects.indexing)
145151
implementation(projects.subprojects.javacServices)
146152
implementation(projects.subprojects.xmlUtils)
147153
implementation(projects.subprojects.projects)
@@ -166,4 +172,4 @@ dependencies {
166172

167173
testImplementation(projects.testing.unit)
168174
androidTestImplementation(projects.testing.android)
169-
}
175+
}

app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ import androidx.core.view.updatePaddingRelative
4949
import com.blankj.utilcode.constant.MemoryConstants
5050
import com.blankj.utilcode.util.ConvertUtils.byte2MemorySize
5151
import com.blankj.utilcode.util.FileUtils
52-
import com.blankj.utilcode.util.KeyboardUtils
5352
import com.blankj.utilcode.util.ThreadUtils
5453
import com.github.mikephil.charting.components.AxisBase
5554
import com.github.mikephil.charting.data.Entry

app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import androidx.work.NetworkType
3030
import androidx.work.Operation
3131
import androidx.work.PeriodicWorkRequestBuilder
3232
import androidx.work.WorkManager
33-
import ch.qos.logback.classic.Logger
3433
import com.blankj.utilcode.util.ThrowableUtils.getFullStackTrace
3534
import com.google.android.material.color.DynamicColors
3635
import com.itsaky.androidide.BuildConfig
@@ -44,8 +43,6 @@ import com.itsaky.androidide.events.EditorEventsIndex
4443
import com.itsaky.androidide.events.LspApiEventsIndex
4544
import com.itsaky.androidide.events.LspJavaEventsIndex
4645
import com.itsaky.androidide.events.ProjectsApiEventsIndex
47-
import com.itsaky.androidide.logging.LogcatAppender
48-
import com.itsaky.androidide.logging.encoder.IDELogFormatEncoder
4946
import com.itsaky.androidide.preferences.internal.DevOpsPreferences
5047
import com.itsaky.androidide.preferences.internal.GeneralPreferences
5148
import com.itsaky.androidide.preferences.internal.StatPreferences
@@ -62,18 +59,19 @@ import com.itsaky.androidide.utils.flashError
6259
import com.termux.app.TermuxApplication
6360
import com.termux.shared.reflection.ReflectionUtils
6461
import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
62+
import io.realm.Realm
6563
import kotlinx.coroutines.DelicateCoroutinesApi
6664
import kotlinx.coroutines.GlobalScope
6765
import kotlinx.coroutines.launch
6866
import org.greenrobot.eventbus.EventBus
6967
import org.greenrobot.eventbus.Subscribe
7068
import org.greenrobot.eventbus.ThreadMode
71-
import org.lsposed.hiddenapibypass.HiddenApiBypass
7269
import org.slf4j.LoggerFactory
7370
import java.lang.Thread.UncaughtExceptionHandler
7471
import java.time.Duration
7572
import kotlin.system.exitProcess
7673

74+
7775
class IDEApplication : TermuxApplication() {
7876

7977
private var uncaughtExceptionHandler: UncaughtExceptionHandler? = null
@@ -97,7 +95,8 @@ class IDEApplication : TermuxApplication() {
9795

9896
if (BuildConfig.DEBUG) {
9997
StrictMode.setVmPolicy(
100-
StrictMode.VmPolicy.Builder(StrictMode.getVmPolicy()).penaltyLog().detectAll().build())
98+
StrictMode.VmPolicy.Builder(StrictMode.getVmPolicy()).penaltyLog().detectAll().build()
99+
)
101100
if (DevOpsPreferences.dumpLogs) {
102101
startLogcatReader()
103102
}
@@ -109,6 +108,8 @@ class IDEApplication : TermuxApplication() {
109108

110109
EventBus.getDefault().register(this)
111110

111+
Realm.init(this)
112+
112113
AppCompatDelegate.setDefaultNightMode(GeneralPreferences.uiMode)
113114

114115
if (IThemeManager.getInstance().getCurrentTheme() == IDETheme.MATERIAL_YOU) {
@@ -123,26 +124,6 @@ class IDEApplication : TermuxApplication() {
123124
}
124125
}
125126

126-
private fun handleCrash(thread: Thread, th: Throwable) {
127-
writeException(th)
128-
129-
try {
130-
131-
val intent = Intent()
132-
intent.action = CrashHandlerActivity.REPORT_ACTION
133-
intent.putExtra(CrashHandlerActivity.TRACE_KEY, getFullStackTrace(th))
134-
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
135-
startActivity(intent)
136-
if (uncaughtExceptionHandler != null) {
137-
uncaughtExceptionHandler!!.uncaughtException(thread, th)
138-
}
139-
140-
exitProcess(1)
141-
} catch (error: Throwable) {
142-
log.error("Unable to show crash handler activity", error)
143-
}
144-
}
145-
146127
fun showChangelog() {
147128
val intent = Intent(Intent.ACTION_VIEW)
148129
var version = BuildInfo.VERSION_NAME_SIMPLE
@@ -168,14 +149,17 @@ class IDEApplication : TermuxApplication() {
168149

169150
val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
170151
val request = PeriodicWorkRequestBuilder<StatUploadWorker>(Duration.ofHours(24)).setInputData(
171-
AndroidIDEStats.statData.toInputData()).setConstraints(constraints)
152+
AndroidIDEStats.statData.toInputData()
153+
).setConstraints(constraints)
172154
.addTag(StatUploadWorker.WORKER_WORK_NAME).build()
173155

174156
val workManager = WorkManager.getInstance(this)
175157

176158
log.info("reportStatsIfNecessary: Enqueuing StatUploadWorker...")
177-
val operation = workManager.enqueueUniquePeriodicWork(StatUploadWorker.WORKER_WORK_NAME,
178-
ExistingPeriodicWorkPolicy.UPDATE, request)
159+
val operation = workManager.enqueueUniquePeriodicWork(
160+
StatUploadWorker.WORKER_WORK_NAME,
161+
ExistingPeriodicWorkPolicy.UPDATE, request
162+
)
179163

180164
operation.state.observeForever(object : Observer<Operation.State> {
181165
override fun onChanged(value: Operation.State) {
@@ -185,22 +169,6 @@ class IDEApplication : TermuxApplication() {
185169
})
186170
}
187171

188-
private fun startLogcatReader() {
189-
if (ideLogcatReader != null) {
190-
// already started
191-
return
192-
}
193-
194-
log.info("Starting logcat reader...")
195-
ideLogcatReader = IDELogcatReader().also { it.start() }
196-
}
197-
198-
private fun stopLogcatReader() {
199-
log.info("Stopping logcat reader...")
200-
ideLogcatReader?.stop()
201-
ideLogcatReader = null
202-
}
203-
204172
@Subscribe(threadMode = ThreadMode.MAIN)
205173
fun onPrefChanged(event: PreferenceChangeEvent) {
206174
val enabled = event.value as? Boolean?
@@ -230,6 +198,26 @@ class IDEApplication : TermuxApplication() {
230198
}
231199
}
232200

201+
private fun handleCrash(thread: Thread, th: Throwable) {
202+
writeException(th)
203+
204+
try {
205+
206+
val intent = Intent()
207+
intent.action = CrashHandlerActivity.REPORT_ACTION
208+
intent.putExtra(CrashHandlerActivity.TRACE_KEY, getFullStackTrace(th))
209+
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
210+
startActivity(intent)
211+
if (uncaughtExceptionHandler != null) {
212+
uncaughtExceptionHandler!!.uncaughtException(thread, th)
213+
}
214+
215+
exitProcess(1)
216+
} catch (error: Throwable) {
217+
log.error("Unable to show crash handler activity", error)
218+
}
219+
}
220+
233221
private fun cancelStatUploadWorker() {
234222
log.info("Opted-out of stat collection. Cancelling StatUploadWorker if enqueued...")
235223
val operation = WorkManager.getInstance(this)
@@ -242,6 +230,22 @@ class IDEApplication : TermuxApplication() {
242230
})
243231
}
244232

233+
private fun startLogcatReader() {
234+
if (ideLogcatReader != null) {
235+
// already started
236+
return
237+
}
238+
239+
log.info("Starting logcat reader...")
240+
ideLogcatReader = IDELogcatReader().also { it.start() }
241+
}
242+
243+
private fun stopLogcatReader() {
244+
log.info("Stopping logcat reader...")
245+
ideLogcatReader?.stop()
246+
ideLogcatReader = null
247+
}
248+
245249
companion object {
246250

247251
private val log = LoggerFactory.getLogger(IDEApplication::class.java)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* This file is part of AndroidIDE.
3+
*
4+
* AndroidIDE is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* AndroidIDE is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.itsaky.androidide.indexing
19+
20+
import io.realm.RealmObject
21+
import io.realm.annotations.PrimaryKey
22+
import io.realm.annotations.RealmField
23+
import io.realm.annotations.Required
24+
25+
/**
26+
* An entity to store information about all registered box stores.
27+
*
28+
* @author Akash Yadav
29+
*/
30+
data class DatabaseEntity(
31+
@Required
32+
@PrimaryKey
33+
@RealmField("path")
34+
var path: String = "",
35+
36+
@Required
37+
@RealmField("name")
38+
var name: String = "",
39+
40+
@Required
41+
@RealmField("directory")
42+
var directory: String = "",
43+
) : RealmObject()
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* This file is part of AndroidIDE.
3+
*
4+
* AndroidIDE is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* AndroidIDE is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.itsaky.androidide.indexing
19+
20+
import com.google.auto.service.AutoService
21+
import com.itsaky.androidide.utils.Environment
22+
import io.realm.Realm
23+
import io.realm.RealmConfiguration
24+
import org.slf4j.LoggerFactory
25+
26+
/**
27+
* Default implementation of [IRealmProvider].
28+
*
29+
* @author Akash Yadav
30+
*/
31+
@AutoService(IRealmProvider::class)
32+
@Suppress("unused")
33+
class RealmProviderImpl : IRealmProvider {
34+
35+
companion object {
36+
private val log = LoggerFactory.getLogger(RealmProviderImpl::class.java)
37+
38+
// must be a relative path, with no special characters except '_' '-' and '/' (path sep)
39+
private val dbNameRegex = Regex("^[a-zA-Z0-9_\\-/]+$")
40+
private const val MASTER_DB_NAME = "master"
41+
private const val MASTER_DB_PATH = "/${MASTER_DB_NAME}"
42+
}
43+
44+
private val masterDb = createDb(MASTER_DB_PATH, null)
45+
46+
override fun get(path: String, config: (RealmConfiguration.Builder.() -> Unit)?): Realm {
47+
require(path != MASTER_DB_PATH) {
48+
"Master DB is internal to AndroidIDE"
49+
}
50+
51+
return createDb(path, config)
52+
}
53+
54+
private fun createDb(path: String, confFunc: (RealmConfiguration.Builder.() -> Unit)?): Realm {
55+
val (parentPath, name) = validateDbPath(path)
56+
57+
val configBuilder = RealmConfiguration.Builder()
58+
confFunc?.also { configure -> configBuilder.configure() }
59+
60+
var dbDir = Environment.REALM_DB_DIR
61+
if (parentPath.isNotEmpty()) {
62+
dbDir = dbDir.resolve(parentPath)
63+
}
64+
65+
val dbName = "${name}.realm"
66+
val config = configBuilder
67+
.name(dbName)
68+
.directory(dbDir)
69+
.allowQueriesOnUiThread(false)
70+
.allowWritesOnUiThread(false)
71+
.compactOnLaunch()
72+
.build()
73+
74+
log.info("Creating DB at $dbDir/$dbName")
75+
76+
masterDb.executeTransactionAsync { realm ->
77+
realm.insertOrUpdate(DatabaseEntity(name = name, path = path, directory = dbDir.absolutePath))
78+
}
79+
80+
return Realm.getInstance(config)
81+
}
82+
83+
private fun validateDbPath(path: String): Pair<String, String> {
84+
require(path.matches(dbNameRegex)) {
85+
"Invalid DB path: $path"
86+
}
87+
88+
val idx = path.indexOfLast { it == IRealmProvider.PATH_SEPARATOR }
89+
require(idx > 0) {
90+
"Invalid DB path: $path"
91+
}
92+
93+
val parentPath = path.substring(0, idx)
94+
val name = path.substring(idx + 1)
95+
96+
if (name == MASTER_DB_NAME) {
97+
require(parentPath.isEmpty()) {
98+
"Master DB must not have any parent path"
99+
}
100+
}
101+
102+
return parentPath to name
103+
}
104+
}

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ buildscript {
4141
dependencies {
4242
classpath(libs.kotlin.gradle.plugin)
4343
classpath(libs.nav.safe.args.gradle.plugin)
44+
classpath(libs.realm.gradle.plugin)
4445
}
4546
}
4647

0 commit comments

Comments
 (0)