From 8a557a7da48461249752dfe9bc7545e9a9706bdc Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 30 Jul 2025 04:41:59 +0000
Subject: [PATCH 1/3] Initial plan
From 778af79eccc8e7ea2a7a7769722aae325d3c7348 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 30 Jul 2025 04:50:09 +0000
Subject: [PATCH 2/3] Complete Android project structure with JavaScript
execution engine
Co-authored-by: rushhiii <142855385+rushhiii@users.noreply.github.com>
---
.gitignore | 38 ++++++
README.md | 112 ++++++++++++++++++
app/build.gradle | 58 +++++++++
app/proguard-rules.pro | 28 +++++
app/src/main/AndroidManifest.xml | 36 ++++++
.../com/scriptabledroid/app/MainActivity.kt | 105 ++++++++++++++++
.../java/com/scriptabledroid/app/Script.kt | 9 ++
.../com/scriptabledroid/app/ScriptAdapter.kt | 48 ++++++++
.../app/ScriptEditorActivity.kt | 111 +++++++++++++++++
.../com/scriptabledroid/app/ScriptEngine.kt | 73 ++++++++++++
.../com/scriptabledroid/app/ScriptStorage.kt | 88 ++++++++++++++
app/src/main/res/layout/activity_main.xml | 49 ++++++++
.../res/layout/activity_script_editor.xml | 82 +++++++++++++
app/src/main/res/layout/item_script.xml | 69 +++++++++++
app/src/main/res/mipmap-hdpi/ic_launcher.png | 0
.../res/mipmap-hdpi/ic_launcher_round.png | 0
app/src/main/res/mipmap-mdpi/ic_launcher.png | 0
.../res/mipmap-mdpi/ic_launcher_round.png | 0
app/src/main/res/mipmap-xhdpi/ic_launcher.png | 0
.../res/mipmap-xhdpi/ic_launcher_round.png | 0
.../main/res/mipmap-xxhdpi/ic_launcher.png | 0
.../res/mipmap-xxhdpi/ic_launcher_round.png | 0
.../main/res/mipmap-xxxhdpi/ic_launcher.png | 0
.../res/mipmap-xxxhdpi/ic_launcher_round.png | 0
app/src/main/res/values/colors.xml | 10 ++
app/src/main/res/values/strings.xml | 18 +++
app/src/main/res/values/themes.xml | 17 +++
app/src/main/res/xml/backup_rules.xml | 4 +
.../main/res/xml/data_extraction_rules.xml | 9 ++
build.gradle | 5 +
gradle/wrapper/gradle-wrapper.properties | 5 +
settings.gradle | 17 +++
32 files changed, 991 insertions(+)
create mode 100644 .gitignore
create mode 100644 app/build.gradle
create mode 100644 app/proguard-rules.pro
create mode 100644 app/src/main/AndroidManifest.xml
create mode 100644 app/src/main/java/com/scriptabledroid/app/MainActivity.kt
create mode 100644 app/src/main/java/com/scriptabledroid/app/Script.kt
create mode 100644 app/src/main/java/com/scriptabledroid/app/ScriptAdapter.kt
create mode 100644 app/src/main/java/com/scriptabledroid/app/ScriptEditorActivity.kt
create mode 100644 app/src/main/java/com/scriptabledroid/app/ScriptEngine.kt
create mode 100644 app/src/main/java/com/scriptabledroid/app/ScriptStorage.kt
create mode 100644 app/src/main/res/layout/activity_main.xml
create mode 100644 app/src/main/res/layout/activity_script_editor.xml
create mode 100644 app/src/main/res/layout/item_script.xml
create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png
create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png
create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
create mode 100644 app/src/main/res/values/colors.xml
create mode 100644 app/src/main/res/values/strings.xml
create mode 100644 app/src/main/res/values/themes.xml
create mode 100644 app/src/main/res/xml/backup_rules.xml
create mode 100644 app/src/main/res/xml/data_extraction_rules.xml
create mode 100644 build.gradle
create mode 100644 gradle/wrapper/gradle-wrapper.properties
create mode 100644 settings.gradle
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a8a763c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,38 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
+
+# Android Studio
+*.iml
+.idea/
+
+# Build
+build/
+*/build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
\ No newline at end of file
diff --git a/README.md b/README.md
index 934f52f..cf97a2f 100644
--- a/README.md
+++ b/README.md
@@ -15,3 +15,115 @@
> * Power users looking for customizable widget logic
> * Anyone who wishes Scriptable existed on Android
+## Features
+
+- **JavaScript Script Editor**: Write and edit JavaScript code with syntax highlighting
+- **Script Execution**: Run JavaScript scripts with access to Android APIs
+- **Battery Information**: Access battery level and charging state through JavaScript
+- **Script Management**: Save, edit, and organize your scripts
+- **System Integration**: Built-in APIs for device information and notifications
+
+## Getting Started
+
+### Prerequisites
+
+- Android Studio Arctic Fox (2020.3.1) or later
+- Android SDK API level 21 or higher
+- Java 8 or higher
+
+### Building the Project
+
+1. Clone the repository:
+```bash
+git clone https://github.com/rushhiii/ScriptableDroid.git
+cd ScriptableDroid
+```
+
+2. Open the project in Android Studio
+
+3. Sync the project with Gradle files
+
+4. Build and run the app on your device or emulator
+
+### Project Structure
+
+```
+ScriptableDroid/
+├── app/
+│ ├── src/main/
+│ │ ├── java/com/scriptabledroid/app/
+│ │ │ ├── MainActivity.kt # Main activity with script list
+│ │ │ ├── ScriptEditorActivity.kt # Script editor with code highlighting
+│ │ │ ├── ScriptEngine.kt # JavaScript execution engine
+│ │ │ ├── ScriptStorage.kt # Script persistence
+│ │ │ ├── ScriptAdapter.kt # RecyclerView adapter for scripts
+│ │ │ └── Script.kt # Script data model
+│ │ ├── res/ # Android resources
+│ │ └── AndroidManifest.xml
+│ └── build.gradle # App-level Gradle config
+├── build.gradle # Project-level Gradle config
+└── settings.gradle # Gradle settings
+```
+
+## JavaScript API
+
+ScriptableDroid provides several built-in JavaScript APIs:
+
+### Device API
+```javascript
+// Get battery level (0-100)
+const batteryLevel = Device.batteryLevel();
+
+// Get battery state ("charging", "discharging", "full", "not_charging", "unknown")
+const batteryState = Device.batteryState();
+```
+
+### Console API
+```javascript
+// Log messages
+console.log("Hello from ScriptableDroid!");
+```
+
+### Notification API (Coming Soon)
+```javascript
+// Create notifications
+Notification.create("Title", "Message body");
+```
+
+## Example Scripts
+
+### Battery Monitor
+```javascript
+// Get battery information
+const batteryLevel = Device.batteryLevel();
+const batteryState = Device.batteryState();
+
+console.log("Battery Level: " + batteryLevel + "%");
+console.log("Battery State: " + batteryState);
+
+"Battery: " + batteryLevel + "% (" + batteryState + ")";
+```
+
+## Contributing
+
+1. Fork the repository
+2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
+3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
+4. Push to the branch (`git push origin feature/AmazingFeature`)
+5. Open a Pull Request
+
+## License
+
+This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
+
+## Roadmap
+
+- [x] Basic JavaScript execution environment
+- [x] Script editor with syntax highlighting
+- [x] Device battery information API
+- [ ] File system access
+- [ ] Network requests support
+- [ ] Home screen widgets
+- [ ] More system APIs (contacts, calendar, etc.)
+- [ ] Script sharing and import/export
+
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..7326232
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,58 @@
+plugins {
+ id 'com.android.application'
+ id 'org.jetbrains.kotlin.android'
+}
+
+android {
+ namespace 'com.scriptabledroid.app'
+ compileSdk 34
+
+ defaultConfig {
+ applicationId "com.scriptabledroid.app"
+ minSdk 21
+ targetSdk 34
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+ buildFeatures {
+ viewBinding true
+ }
+}
+
+dependencies {
+
+ implementation 'androidx.core:core-ktx:1.12.0'
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'com.google.android.material:material:1.10.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+
+ // Duktape for JavaScript execution
+ implementation 'com.squareup.duktape:duktape-android:1.4.0'
+
+ // For code editor
+ implementation 'io.github.rosemoe.sora-editor:editor:0.23.4'
+ implementation 'io.github.rosemoe.sora-editor:language-javascript:0.23.4'
+
+ // JSON serialization
+ implementation 'com.google.code.gson:gson:2.10.1'
+
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.5'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
+}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..6eb51ff
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,28 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+
+# Keep Duktape classes
+-keep class com.squareup.duktape.** { *; }
+
+# Keep Gson classes
+-keep class com.google.gson.** { *; }
+-keep class com.scriptabledroid.app.Script { *; }
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..bce4f33
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/scriptabledroid/app/MainActivity.kt b/app/src/main/java/com/scriptabledroid/app/MainActivity.kt
new file mode 100644
index 0000000..c4bbb7b
--- /dev/null
+++ b/app/src/main/java/com/scriptabledroid/app/MainActivity.kt
@@ -0,0 +1,105 @@
+package com.scriptabledroid.app
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import androidx.appcompat.app.AppCompatActivity
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.scriptabledroid.app.databinding.ActivityMainBinding
+
+class MainActivity : AppCompatActivity() {
+
+ private lateinit var binding: ActivityMainBinding
+ private lateinit var scriptStorage: ScriptStorage
+ private lateinit var scriptEngine: ScriptEngine
+ private lateinit var scriptAdapter: ScriptAdapter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ scriptStorage = ScriptStorage(this)
+ scriptEngine = ScriptEngine(this)
+
+ setupRecyclerView()
+ setupFab()
+
+ // Create default scripts on first run
+ scriptStorage.createDefaultScripts()
+ loadScripts()
+ }
+
+ private fun setupRecyclerView() {
+ scriptAdapter = ScriptAdapter(
+ scripts = emptyList(),
+ onRunClick = { script -> runScript(script) },
+ onEditClick = { script -> editScript(script) },
+ onDeleteClick = { script -> confirmDeleteScript(script) }
+ )
+
+ binding.recyclerViewScripts.apply {
+ layoutManager = LinearLayoutManager(this@MainActivity)
+ adapter = scriptAdapter
+ }
+ }
+
+ private fun setupFab() {
+ binding.fabNewScript.setOnClickListener {
+ createNewScript()
+ }
+ }
+
+ private fun loadScripts() {
+ val scripts = scriptStorage.getAllScripts()
+ scriptAdapter.updateScripts(scripts)
+
+ binding.textViewEmpty.visibility = if (scripts.isEmpty()) View.VISIBLE else View.GONE
+ binding.recyclerViewScripts.visibility = if (scripts.isEmpty()) View.GONE else View.VISIBLE
+ }
+
+ private fun runScript(script: Script) {
+ val result = scriptEngine.executeScript(script.content)
+
+ MaterialAlertDialogBuilder(this)
+ .setTitle("Script Output: ${script.name}")
+ .setMessage(result)
+ .setPositiveButton("OK", null)
+ .show()
+ }
+
+ private fun editScript(script: Script) {
+ val intent = Intent(this, ScriptEditorActivity::class.java).apply {
+ putExtra("script_id", script.id)
+ }
+ startActivity(intent)
+ }
+
+ private fun createNewScript() {
+ val intent = Intent(this, ScriptEditorActivity::class.java)
+ startActivity(intent)
+ }
+
+ private fun confirmDeleteScript(script: Script) {
+ MaterialAlertDialogBuilder(this)
+ .setTitle("Delete Script")
+ .setMessage("Are you sure you want to delete '${script.name}'?")
+ .setPositiveButton("Delete") { _, _ ->
+ scriptStorage.deleteScript(script.id)
+ loadScripts()
+ }
+ .setNegativeButton("Cancel", null)
+ .show()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ loadScripts()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ scriptEngine.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/scriptabledroid/app/Script.kt b/app/src/main/java/com/scriptabledroid/app/Script.kt
new file mode 100644
index 0000000..b6f51ba
--- /dev/null
+++ b/app/src/main/java/com/scriptabledroid/app/Script.kt
@@ -0,0 +1,9 @@
+package com.scriptabledroid.app
+
+data class Script(
+ val id: String,
+ val name: String,
+ val content: String,
+ val description: String = "",
+ val lastModified: Long = System.currentTimeMillis()
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/scriptabledroid/app/ScriptAdapter.kt b/app/src/main/java/com/scriptabledroid/app/ScriptAdapter.kt
new file mode 100644
index 0000000..4fb18c1
--- /dev/null
+++ b/app/src/main/java/com/scriptabledroid/app/ScriptAdapter.kt
@@ -0,0 +1,48 @@
+package com.scriptabledroid.app
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.scriptabledroid.app.databinding.ItemScriptBinding
+
+class ScriptAdapter(
+ private var scripts: List