Improved core code

This commit is contained in:
Kevin Rodrigues Borges
2026-04-23 04:30:13 +01:00
parent 5676b67004
commit ae8bed0fda
61 changed files with 3830 additions and 84 deletions

281
README.md Normal file
View File

@@ -0,0 +1,281 @@
# AniyomiBridge Core
A JVM runtime for running Aniyomi (anime/manga streaming) Android extensions on desktop. This project bridges the gap between Android's framework and desktop Java/Kotlin by providing a compatibility layer that lets Aniyomi extensions execute outside of the Android ecosystem.
## Quick Start
```bash
# Build the fat JAR (includes all dependencies)
mvn clean package
# Output: aniyomibridge-core/target/aniyomibridge-core-1.0.0.jar
# Main class: dev.k3vinb5.aniyomibridge.Main
```
## Project Architecture
This is a **multi-module Maven project** with two main modules:
```
aniyomibridge-core/
├── pom.xml # Parent POM — coordinates modules
├── androidcompat/ # Android compatibility layer
│ ├── src/main/java/android/ # Custom Android stub implementations
│ ├── src/main/java/androidx/ # AndroidX stub implementations
│ ├── scripts/get-android.sh # Android SDK JAR download & patch script
│ └── pom.xml
├── aniyomibridge-core/ # Core bridge module
│ ├── src/main/java/ # Java sources (bridge core)
│ ├── src/main/kotlin/ # Kotlin sources (Tachiyomi/Aniyomi interfaces)
│ └── pom.xml
└── assets/ # JavaScript files for extractors
```
### Module: `androidcompat`
Provides Android framework classes on desktop JVM using a **hybrid approach** inspired by [Suwayomi](https://github.com/Suwayomi/Suwayomi-Server):
1. **Base SDK**: Downloads the official Android SDK `android.jar` from [Sable/android-platforms](https://github.com/Sable/android-platforms)
2. **Custom Stubs**: Implements desktop-specific behavior for classes that need it (e.g., `Context`, `WebView`, `SharedPreferences`)
3. **Jar Patching**: Removes SDK classes that have custom implementations to prevent conflicts
**Result**: A merged Android API where ~4,000 SDK classes work as-is, and ~30+ critical classes have desktop-aware implementations.
### Module: `aniyomibridge-core`
The core bridge that loads and executes Aniyomi/Tachiyomi extensions.
**Key Classes**:
- `AniyomiBridge.java` — Main API for loading/unloading extensions
- `ExtensionLoader.java` — Loads extension classes from JAR files
- `ApkUtils.java` — Converts Android APK → JAR using dex2jar
**Extension Loading Flow**:
1. Download APK from URL
2. `ApkUtils.dex2jar()` converts APK → JAR
3. `ExtensionLoader.loadClassFromJar()` loads the main extension class
4. Cast to `AnimeHttpSource` or `CatalogueSource`
5. Store in `animeSources`/`mangaSources` maps
## The Build Process Explained
When you type `mvn clean package`, here's exactly what happens, phase by phase, across both modules.
### Module Build Order
Maven builds modules in dependency order:
1. **Parent POM** (coordinates children, does not produce a JAR)
2. **`androidcompat`** (no internal dependencies)
3. **`aniyomibridge-core`** (depends on `androidcompat`)
`androidcompat` **must** finish its `package` phase before `aniyomibridge-core` can even start compiling.
### Phase-by-Phase Breakdown
#### 1. `clean` phase
**Plugin:** `maven-clean-plugin`
- Deletes `androidcompat/target/` and `aniyomibridge-core/target/`
- Fresh slate. Any previously downloaded `android.jar` or compiled classes are removed.
#### 2. `validate` through `process-sources`
**Plugins:** `maven-compiler-plugin`, `kotlin-maven-plugin` (configuration only)
- Maven validates all POMs are well-formed
- Standard lifecycle phases proceed normally
#### 3. `generate-resources` phase *(androidcompat only)*
**Plugin:** `exec-maven-plugin`
```xml
<phase>generate-resources</phase>
<goal>exec</goal>
```
- Maven runs `scripts/get-android.sh`
- The script:
1. Downloads `android.jar` from Sable/android-platforms (if not cached)
2. Verifies it's a valid JAR
3. Uses `zip -d` to **delete** classes that have custom stubs (e.g., `android.content.Context`, `android.app.Application`)
4. Saves result as `androidcompat/target/patched-android.jar`
> **Result:** A stripped Android SDK JAR with "holes" where custom implementations will go.
#### 4. `process-resources` phase *(androidcompat only)*
**Plugin:** `maven-antrun-plugin`
```xml
<phase>process-resources</phase>
```
- Maven runs the Ant task that **unpacks** `patched-android.jar` into `androidcompat/target/classes/`
- This dumps ~4,000 `.class` files (the SDK stubs) into the build output directory
> **Result:** `androidcompat/target/classes/` now contains all Android SDK classes you *didn't* write custom stubs for.
#### 5. `compile` phase
**Plugins:** `maven-compiler-plugin` + `kotlin-maven-plugin`
- Compiles custom Java stubs from `androidcompat/src/main/java/` into `androidcompat/target/classes/`
- Compiles Kotlin sources too
- **Critical:** Compiled output goes to the **same** `target/classes/` directory, so custom stubs **overwrite** the SDK classes that were unpacked there
> **Result:** `target/classes/` now contains:
> - SDK classes (the ones you don't override)
> - Your custom stubs (overwriting the SDK versions)
> - Your project-specific classes
This is the **hybrid magic** — the directory contains a merged Android API.
#### 6. `process-classes` through `prepare-package`
- Nothing special in this project
- Annotation processors or bytecode weaving would happen here if configured
#### 7. `package` phase
Two different things happen per module:
##### In `androidcompat`:
**Plugin:** `maven-jar-plugin`
- Packages `target/classes/` into `androidcompat/target/androidcompat-1.0.0.jar`
- This JAR contains the merged Android API (SDK + custom stubs)
##### In `aniyomibridge-core`:
**Plugins:** `maven-jar-plugin` → `maven-shade-plugin`
1. **maven-jar-plugin** creates the "thin" JAR: `aniyomibridge-core-1.0.0.jar`
2. **maven-shade-plugin** then runs:
- Takes the thin JAR
- **Unpacks** the `androidcompat` dependency JAR into it
- **Unpacks** all other dependencies (OkHttp, Kotlin stdlib, Gson, etc.)
- Applies filter rules:
- `minimizeJar=true` strips unused classes from dependencies
- A `<filter>` for `androidcompat` forces **all** its classes to be included (otherwise they'd be stripped because extensions load them dynamically, not via direct references in core code)
- Excludes `Main.class` from the final JAR (consumed by Flutter externally)
- Excludes signing files (`*.SF`, `*.DSA`, `*.RSA`) and `module-info.class`
- Creates the **fat JAR**: `aniyomibridge-core/target/aniyomibridge-core-1.0.0.jar`
> **Result:** A single ~90MB JAR containing your core code + the entire merged Android API + all dependencies.
### Visual Timeline
```
$ mvn clean package
[MODULE: parent pom]
validate → compile → package (pom packaging, just validates)
[MODULE: androidcompat]
clean → delete target/
validate → check pom
...
generate-resources → exec-maven-plugin runs get-android.sh
↳ downloads & patches android.jar
process-resources → maven-antrun-plugin unpacks patched JAR
↳ target/classes/ ← 4,000 SDK .class files
compile → maven-compiler-plugin compiles custom stubs
↳ target/classes/ ← custom stubs OVERWRITE SDK versions
...
package → maven-jar-plugin creates androidcompat-1.0.0.jar
↳ contains merged Android API
[MODULE: aniyomibridge-core]
validate → check pom
...
compile → compile core sources (can reference androidcompat classes)
...
package → maven-jar-plugin creates thin JAR
→ maven-shade-plugin creates fat JAR
↳ unpacks androidcompat + all deps
↳ filters: include ALL androidcompat, exclude Main.class
↳ outputs aniyomibridge-core-1.0.0.jar (~90MB)
```
### Why This Order Matters
1. **`androidcompat` must build first** — `aniyomibridge-core` declares it as a dependency, so Maven enforces this order automatically.
2. **`generate-resources` must happen before `process-resources`** — You can't unpack the JAR until it exists. The download script creates it during `generate-resources`, then Ant unpacks it during `process-resources`.
3. **Unpacking must happen before `compile`** — The compiler needs to see the Android SDK classes to resolve imports in your custom stubs. If `maven-antrun-plugin` ran after `compile`, compilation would fail with "cannot find symbol" for Android classes.
4. **Custom stubs overwrite SDK classes in `target/classes/`** — This is by design. The compiler writes to the same directory that Ant unpacked into, so your `Context.java` overwrites the SDK's `Context.class`.
5. **`minimizeJar` + filter is critical** — Without the shade filter for `androidcompat`, Maven Shade would see that `aniyomibridge-core` never directly references `android.graphics.Bitmap` (extensions load it via reflection/ClassLoader), so it would strip it out. The filter forces inclusion of the entire merged Android API.
## Key Technologies
| Technology | Purpose |
|-----------|---------|
| **Android SDK JAR (patched)** | Base Android API classes |
| **dex2jar** | Converts Android APK DEX → JAR |
| **HtmlUnit / JavaFX WebView** | Desktop WebView implementation |
| **OkHttp + DoH** | HTTP client for extensions |
| **Kotlin Coroutines** | Async operations |
| **kotlinx-serialization-json** | JSON handling |
| **Gson** | JSON preference storage |
| **ByteBuddy** | Runtime bytecode patching |
| **Rhino / GraalVM JS** | JavaScript execution |
## Build Details
- **Java Version**: 17 (source and target)
- **Kotlin Version**: 2.1.0
- **Build Tool**: Maven (multi-module)
- **Packaging**: Shade plugin creates minimized fat JAR
## Development Scripts
| Script | Purpose |
|--------|---------|
| `generate-new-core-linux.sh` | Build + copy JAR to Flutter app assets (Linux path) |
| `generate-new-core-mac.sh` | Build + copy JAR to Flutter app assets (Mac path) |
| `androidcompat/scripts/get-android.sh` | Download and patch Android SDK JAR |
Both build scripts copy the output to a sibling project `k3vinb5_aniyomi_bridge/assets/`.
## IntelliJ IDEA Setup
See [`androidcompat/README.md`](androidcompat/README.md) for detailed IntelliJ setup instructions, including how to get code navigation working for the Android SDK stubs.
Quick version:
1. Run `mvn clean compile -pl androidcompat` once to download the SDK
2. Right-click `androidcompat/pom.xml` → **Maven** → **Reload Project**
3. Ctrl+Click on Android classes to navigate between SDK stubs and custom implementations
## Adding New Android Stubs
When an extension requires an Android class that doesn't exist or crashes:
1. **Identify** which class needs a desktop implementation
2. **Create** the stub in `androidcompat/src/main/java/android/<package>/`
3. **Add** the class path to `scripts/get-android.sh` in the `CUSTOM_CLASSES` array
4. **Rebuild** with `mvn clean compile -pl androidcompat`
See [`androidcompat/README.md`](androidcompat/README.md) for more details on the three options: minimal stub, full desktop implementation, or SDK class.
## Troubleshooting
### `ClassNotFoundException` for Android classes
- Check if the class is in the downloaded `android.jar`
- If not, create a stub in `src/main/java/android/...`
- Add the class to `CUSTOM_CLASSES` in `get-android.sh`
### `MethodNotFoundError`
- The Android SDK version might be too old
- Update `ANDROID_SDK_VERSION` in `get-android.sh`
- Or create a custom stub with the required method
### Build fails with "cannot find symbol android.***"
- The patched `android.jar` hasn't been unpacked yet
- Run `mvn clean compile -pl androidcompat` first
- Check that `androidcompat/target/classes/` contains `.class` files
## References
- [Suwayomi's AndroidCompat](https://github.com/Suwayomi/Suwayomi-Server/tree/master/AndroidCompat) — Inspiration for the hybrid stub approach
- [Sable/android-platforms](https://github.com/Sable/android-platforms) — Android SDK JAR source
- [dex2jar](https://github.com/pxb1988/dex2jar) — APK to JAR conversion
- [Android SDK Reference](https://developer.android.com/reference/)

View File

@@ -87,6 +87,55 @@ The androidcompat module is automatically included as a dependency in the core m
3. Compiles custom stubs alongside the patched JAR
4. Packages everything into the final JAR
## IntelliJ IDEA Setup (Code Navigation)
The stripped `android.jar` (SDK classes minus our stubs) is added as a **system dependency** in `pom.xml`. This lets IntelliJ index it so you can navigate Android SDK source code with Ctrl+Click.
### First-Time Setup
1. **Download the JAR** (one-time):
```bash
cd androidcompat
./scripts/get-android.sh
```
Or just run a build:
```bash
mvn clean compile -pl androidcompat
```
2. **Reload the Maven project** in IntelliJ:
- Right-click `androidcompat/pom.xml` → **Maven** → **Reload Project**
- Or press `Ctrl+Shift+O` (Linux/Windows) / `Cmd+Shift+O` (Mac)
3. **Verify it's working**:
- Open `androidcompat/src/main/java/android/content/Context.java`
- Press `Ctrl+B` on `ApplicationInfo` (or any SDK class not in our stubs)
- IntelliJ should decompile and show the SDK source
### What You'll See
In the **Project Structure** (`Ctrl+Alt+Shift+S`) → **Libraries**, you should see:
```
Maven: com.google.android:android-sdk-stripped:34
└── androidcompat/target/android.jar
```
This JAR contains **only SDK classes we haven't stubbed** — so when you navigate to `android.app.Activity`, you see the real Android implementation, but when you navigate to `android.content.Context`, you see **our stub**.
### Troubleshooting
**"Library not found" or red text in pom.xml:**
- The JAR hasn't been downloaded yet. Run `./scripts/get-android.sh` or `mvn clean compile`.
**"Cannot resolve symbol" for Android classes:**
- Reload the Maven project: right-click `pom.xml` → **Maven** → **Reload Project**
- Or: **File** → **Invalidate Caches** → **Invalidate and Restart**
**Want to see our stubs instead of SDK classes?**
- Our stubs are regular source files in `src/main/java/android/...`
- If IntelliJ shows the decompiled SDK version, it means that class is **not in our stubs** (which is useful info!)
- To stub it, create the class in `src/main/java/android/<package>/` and add it to `get-android.sh`
### Skipping the Download
If you already have `android.jar` downloaded or want to skip the download:

View File

@@ -68,14 +68,14 @@
<groupId>org.graalvm.polyglot</groupId>
<artifactId>polyglot</artifactId>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js-scriptengine</artifactId>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js-language</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.graalvm.js</groupId>-->
<!-- <artifactId>js-scriptengine</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.graalvm.js</groupId>-->
<!-- <artifactId>js-language</artifactId>-->
<!-- </dependency>-->
<!-- RxJava -->
<dependency>
@@ -88,6 +88,24 @@
<artifactId>rxrelay</artifactId>
<version>1.2.0</version>
</dependency>
<!--
Android SDK JAR (stripped - only SDK classes we don't stub).
Added as a system dependency so IntelliJ IDEA indexes it for
code navigation and completion.
NOTE: The JAR is downloaded during `mvn clean compile` via the
get-android.sh script. If IntelliJ shows it as missing, run:
cd androidcompat && ./scripts/get-android.sh
Then right-click pom.xml → Maven → Reload Project.
-->
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android-sdk-stripped</artifactId>
<version>${android.sdk.version}</version>
<scope>system</scope>
<systemPath>${project.build.directory}/android.jar</systemPath>
</dependency>
</dependencies>
<build>

View File

@@ -31,8 +31,6 @@ CUSTOM_CLASSES=(
"android/os/Build.class"
"android/os/Environment.class"
"android/os/Environment\$*.class"
"android/os/Bundle.class"
"android/os/Bundle\$*.class"
"android/graphics/Bitmap.class"
"android/graphics/Bitmap\$*.class"
"android/graphics/Canvas.class"
@@ -52,6 +50,70 @@ CUSTOM_CLASSES=(
"android/util/Log.class"
"android/util/Base64.class"
"android/annotation/SuppressLint.class"
"android/content/pm/PackageManager.class"
"android/content/pm/PackageManager\$*.class"
"android/content/res/AssetManager.class"
"android/content/res/AssetManager\$*.class"
"android/content/res/Resources.class"
"android/content/res/Resources\$*.class"
"android/content/ContentResolver.class"
"android/content/ContentResolver\$*.class"
"android/view/Display.class"
"android/view/Display\$*.class"
"android/location/LocationManager.class"
"android/location/LocationManager\$*.class"
"android/net/ConnectivityManager.class"
"android/net/ConnectivityManager\$*.class"
"android/app/ActivityManager.class"
"android/app/ActivityManager\$*.class"
"android/app/AlarmManager.class"
"android/app/AlarmManager\$*.class"
"android/app/NotificationManager.class"
"android/app/NotificationManager\$*.class"
"android/app/SearchManager.class"
"android/app/SearchManager\$*.class"
"android/app/KeyguardManager.class"
"android/app/KeyguardManager\$*.class"
"android/app/UiModeManager.class"
"android/app/UiModeManager\$*.class"
"android/app/DownloadManager.class"
"android/app/DownloadManager\$*.class"
"android/os/PowerManager.class"
"android/os/PowerManager\$*.class"
"android/os/Vibrator.class"
"android/os/BatteryManager.class"
"android/os/BatteryManager\$*.class"
"android/media/AudioManager.class"
"android/media/AudioManager\$*.class"
"android/telephony/TelephonyManager.class"
"android/telephony/TelephonyManager\$*.class"
"android/content/ClipboardManager.class"
"android/view/WindowManager.class"
"android/view/LayoutInflater.class"
"android/view/inputmethod/InputMethodManager.class"
"android/hardware/display/DisplayManager.class"
"android/hardware/display/DisplayManager\$*.class"
"android/hardware/SensorManager.class"
"android/hardware/SensorManager\$*.class"
"android/os/storage/StorageManager.class"
"android/os/storage/StorageManager\$*.class"
"android/net/wifi/WifiManager.class"
"android/net/wifi/WifiManager\$*.class"
"android/net/wifi/p2p/WifiP2pManager.class"
"android/net/wifi/p2p/WifiP2pManager\$*.class"
"android/bluetooth/BluetoothManager.class"
"android/accounts/AccountManager.class"
"android/accounts/AccountManager\$*.class"
"android/appwidget/AppWidgetManager.class"
"android/appwidget/AppWidgetManager\$*.class"
"android/nfc/NfcManager.class"
"android/content/pm/ShortcutManager.class"
"android/view/accessibility/AccessibilityManager.class"
"android/view/accessibility/AccessibilityManager\$*.class"
"android/app/job/JobScheduler.class"
"android/app/job/JobScheduler\$*.class"
"android/app/admin/DevicePolicyManager.class"
"android/app/admin/DevicePolicyManager\$*.class"
)
echo "=== Android SDK Download and Patch Script ==="

View File

@@ -0,0 +1,46 @@
package android.accounts;
/**
* Minimal AccountManager stub for desktop JVM.
*/
public class AccountManager {
public AccountManager() {
}
public android.accounts.Account[] getAccounts() {
return new android.accounts.Account[0];
}
public android.accounts.Account[] getAccountsByType(String type) {
return new android.accounts.Account[0];
}
public android.accounts.Account getAccountsByTypeAndFeatures(String type, String[] features, android.accounts.AccountManagerCallback<android.accounts.Account[]> callback, android.os.Handler handler) {
return null;
}
public java.lang.String getUserData(android.accounts.Account account, String key) {
return null;
}
public java.lang.String getPassword(android.accounts.Account account) {
return null;
}
public java.lang.String peekAuthToken(android.accounts.Account account, String authTokenType) {
return null;
}
public void setUserData(android.accounts.Account account, String key, String value) {
// No-op on desktop
}
public void addAccountExplicitly(android.accounts.Account account, String password, android.os.Bundle userdata) {
// No-op on desktop
}
public void removeAccount(android.accounts.Account account, android.accounts.AccountManagerCallback<android.os.Bundle> callback, android.os.Handler handler) {
// No-op on desktop
}
}

View File

@@ -0,0 +1,44 @@
package android.app;
/**
* Minimal ActivityManager stub for desktop JVM.
*/
public class ActivityManager {
public ActivityManager() {
}
public static boolean isUserAMonkey() {
return false;
}
public static boolean isRunningInTestHarness() {
return false;
}
public android.app.ActivityManager.MemoryInfo getMemoryInfo(android.app.ActivityManager.MemoryInfo outInfo) {
if (outInfo == null) {
outInfo = new android.app.ActivityManager.MemoryInfo();
}
outInfo.availMem = Runtime.getRuntime().freeMemory();
outInfo.totalMem = Runtime.getRuntime().totalMemory();
outInfo.threshold = 0;
outInfo.lowMemory = false;
return outInfo;
}
public int getMemoryClass() {
return 256;
}
public int getLargeMemoryClass() {
return 512;
}
public static class MemoryInfo {
public long availMem;
public long totalMem;
public long threshold;
public boolean lowMemory;
}
}

View File

@@ -0,0 +1,51 @@
package android.app;
/**
* Minimal AlarmManager stub for desktop JVM.
*/
public class AlarmManager {
public static final int RTC_WAKEUP = 0;
public static final int RTC = 1;
public static final int ELAPSED_REALTIME_WAKEUP = 2;
public static final int ELAPSED_REALTIME = 3;
public AlarmManager() {
}
public void set(int type, long triggerAtMillis, android.app.PendingIntent operation) {
// No-op on desktop
}
public void setExact(int type, long triggerAtMillis, android.app.PendingIntent operation) {
// No-op on desktop
}
public void setRepeating(int type, long triggerAtMillis, long intervalMillis, android.app.PendingIntent operation) {
// No-op on desktop
}
public void setInexactRepeating(int type, long triggerAtMillis, long intervalMillis, android.app.PendingIntent operation) {
// No-op on desktop
}
public void cancel(android.app.PendingIntent operation) {
// No-op on desktop
}
public void cancel(android.app.AlarmManager.OnAlarmListener listener) {
// No-op on desktop
}
public void setTime(long millis) {
// No-op on desktop
}
public void setTimeZone(String timeZone) {
// No-op on desktop
}
public interface OnAlarmListener {
void onAlarm();
}
}

View File

@@ -1,5 +1,6 @@
package android.app;
import android.content.ApplicationContext;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferencesImpl;
@@ -14,15 +15,20 @@ public class Application {
private final Map<String, SharedPreferences> prefs = new HashMap<>();
private final Map<Long, PreferenceScreen> preferenceScreens = new HashMap<>();
private final Context context = new Context();
private final ApplicationContext applicationContext;
private Application() {
this.applicationContext = new ApplicationContext(this);
}
public static Application getInstance() {
return INSTANCE;
}
public Context getApplicationContext() {
return applicationContext;
}
public SharedPreferences getSharedPreferences(String name, int mode) {
if (prefs.containsKey(name + mode)) {
return prefs.get(name + mode);
@@ -36,7 +42,7 @@ public class Application {
if (preferenceScreens.containsKey(id)) {
return preferenceScreens.get(id);
}
PreferenceScreen screen = new PreferenceScreen(context, this.getSharedPreferences("source_" + id, Context.MODE_PRIVATE));
PreferenceScreen screen = new PreferenceScreen(applicationContext, this.getSharedPreferences("source_" + id, Context.MODE_PRIVATE));
preferenceScreens.put(id, screen);
return screen;
}

View File

@@ -0,0 +1,95 @@
package android.app;
/**
* Minimal DownloadManager stub for desktop JVM.
*/
public class DownloadManager {
public static final String COLUMN_ID = "_id";
public static final String COLUMN_TITLE = "title";
public static final String COLUMN_DESCRIPTION = "description";
public static final String COLUMN_URI = "uri";
public static final String COLUMN_STATUS = "status";
public static final String COLUMN_REASON = "reason";
public static final String COLUMN_TOTAL_SIZE_BYTES = "total_size";
public static final String COLUMN_BYTES_DOWNLOADED_SO_FAR = "bytes_so_far";
public static final String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
public static final String COLUMN_MEDIA_TYPE = "media_type";
public static final String COLUMN_LOCAL_URI = "local_uri";
public static final int STATUS_PENDING = 1;
public static final int STATUS_RUNNING = 2;
public static final int STATUS_PAUSED = 4;
public static final int STATUS_SUCCESSFUL = 8;
public static final int STATUS_FAILED = 16;
public DownloadManager() {
}
public long enqueue(android.app.DownloadManager.Request request) {
System.err.println("WARNING: DownloadManager.enqueue() called on desktop - not supported");
return -1;
}
public int remove(long... ids) {
return 0;
}
public android.database.Cursor query(android.app.DownloadManager.Query query) {
return null;
}
public android.os.ParcelFileDescriptor openDownloadedFile(long id) {
return null;
}
public android.net.Uri getUriForDownloadedFile(long id) {
return null;
}
public java.lang.String getMimeTypeForDownloadedFile(long id) {
return null;
}
public static class Request {
public Request(android.net.Uri uri) {
}
public android.app.DownloadManager.Request setDestinationUri(android.net.Uri uri) {
return this;
}
public android.app.DownloadManager.Request setDestinationInExternalPublicDir(String dirType, String subPath) {
return this;
}
public android.app.DownloadManager.Request setTitle(CharSequence title) {
return this;
}
public android.app.DownloadManager.Request setDescription(CharSequence description) {
return this;
}
public android.app.DownloadManager.Request setAllowedNetworkTypes(int flags) {
return this;
}
public android.app.DownloadManager.Request addRequestHeader(String header, String value) {
return this;
}
}
public static class Query {
public Query() {
}
public android.app.DownloadManager.Query setFilterById(long... ids) {
return this;
}
public android.app.DownloadManager.Query setFilterByStatus(int flags) {
return this;
}
}
}

View File

@@ -0,0 +1,54 @@
package android.app;
/**
* Minimal KeyguardManager stub for desktop JVM.
*/
public class KeyguardManager {
public KeyguardManager() {
}
public boolean inKeyguardRestrictedInputMode() {
return false;
}
public boolean isKeyguardLocked() {
return false;
}
public boolean isKeyguardSecure() {
return false;
}
public boolean isDeviceLocked() {
return false;
}
public boolean isDeviceSecure() {
return false;
}
public KeyguardManager.KeyguardLock newKeyguardLock(String tag) {
return new KeyguardManager.KeyguardLock();
}
public void requestDismissKeyguard(android.app.Activity activity, KeyguardManager.KeyguardDismissCallback callback) {
// No-op on desktop
}
public static class KeyguardLock {
public void disableKeyguard() {
// No-op
}
public void reenableKeyguard() {
// No-op
}
}
public static class KeyguardDismissCallback {
public void onDismissError() {}
public void onDismissSucceeded() {}
public void onDismissCancelled() {}
}
}

View File

@@ -0,0 +1,54 @@
package android.app;
/**
* Minimal NotificationManager stub for desktop JVM.
*/
public class NotificationManager {
public NotificationManager() {
}
public void notify(int id, android.app.Notification notification) {
// No-op on desktop
}
public void notify(String tag, int id, android.app.Notification notification) {
// No-op on desktop
}
public void cancel(int id) {
// No-op on desktop
}
public void cancel(String tag, int id) {
// No-op on desktop
}
public void cancelAll() {
// No-op on desktop
}
public void createNotificationChannel(android.app.NotificationChannel channel) {
// No-op on desktop
}
public void createNotificationChannels(java.util.List<android.app.NotificationChannel> channels) {
// No-op on desktop
}
public void deleteNotificationChannel(String channelId) {
// No-op on desktop
}
public java.util.List<android.app.NotificationChannel> getNotificationChannels() {
return new java.util.ArrayList<>();
}
public android.app.NotificationChannel getNotificationChannel(String channelId) {
return null;
}
public boolean areNotificationsEnabled() {
return false;
}
}

View File

@@ -0,0 +1,32 @@
package android.app;
/**
* Minimal SearchManager stub for desktop JVM.
*/
public class SearchManager {
public static final String QUERY = "query";
public static final String APP_DATA = "app_data";
public static final String EXTRA_DATA_KEY = "intent_extra_data_key";
public static final String ACTION_KEY = "action_key";
public static final String EXTRA_SELECT_QUERY = "select_query";
public SearchManager() {
}
public void startSearch(String initialQuery, boolean selectInitialQuery, android.content.ComponentName launchActivity, android.os.Bundle appSearchData, boolean globalSearch) {
// No-op on desktop
}
public void triggerSearch(String query, android.content.ComponentName launchActivity, android.os.Bundle appSearchData) {
// No-op on desktop
}
public void stopSearch() {
// No-op on desktop
}
public android.content.Intent getSearchIntent(android.content.ComponentName launchActivity, android.os.Bundle appSearchData, boolean globalSearch) {
return null;
}
}

View File

@@ -0,0 +1,35 @@
package android.app;
/**
* Minimal UiModeManager stub for desktop JVM.
*/
public class UiModeManager {
public static final int MODE_NIGHT_AUTO = 0;
public static final int MODE_NIGHT_NO = 1;
public static final int MODE_NIGHT_YES = 2;
public static final int MODE_NIGHT_CUSTOM = 3;
public UiModeManager() {
}
public void enableCarMode(int flags) {
// No-op on desktop
}
public void disableCarMode(int flags) {
// No-op on desktop
}
public int getCurrentModeType() {
return 1; // UI_MODE_TYPE_NORMAL
}
public void setNightMode(int mode) {
// No-op on desktop
}
public int getNightMode() {
return MODE_NIGHT_NO;
}
}

View File

@@ -0,0 +1,50 @@
package android.app.admin;
/**
* Minimal DevicePolicyManager stub for desktop JVM.
*/
public class DevicePolicyManager {
public DevicePolicyManager() {
}
public boolean isAdminActive(android.content.ComponentName admin) {
return false;
}
public java.util.List<android.content.ComponentName> getActiveAdmins() {
return new java.util.ArrayList<>();
}
public void removeActiveAdmin(android.content.ComponentName admin) {
// No-op on desktop
}
public boolean isDeviceOwnerApp(String packageName) {
return false;
}
public boolean isProfileOwnerApp(String packageName) {
return false;
}
public void setCameraDisabled(android.content.ComponentName admin, boolean disabled) {
// No-op on desktop
}
public boolean getCameraDisabled(android.content.ComponentName admin) {
return false;
}
public void setStorageEncryption(android.content.ComponentName admin, boolean encrypt) {
// No-op on desktop
}
public boolean getStorageEncryption(android.content.ComponentName admin) {
return false;
}
public int getStorageEncryptionStatus() {
return 0;
}
}

View File

@@ -0,0 +1,34 @@
package android.app.job;
/**
* Minimal JobScheduler stub for desktop JVM.
*/
public class JobScheduler {
public static final int RESULT_SUCCESS = 0;
public static final int RESULT_FAILURE = 1;
public JobScheduler() {
}
public int schedule(android.app.job.JobInfo job) {
System.err.println("WARNING: JobScheduler.schedule() called on desktop - not supported");
return RESULT_FAILURE;
}
public void cancel(int jobId) {
// No-op on desktop
}
public void cancelAll() {
// No-op on desktop
}
public java.util.List<android.app.job.JobInfo> getAllPendingJobs() {
return new java.util.ArrayList<>();
}
public android.app.job.JobInfo getPendingJob(int jobId) {
return null;
}
}

View File

@@ -0,0 +1,34 @@
package android.appwidget;
/**
* Minimal AppWidgetManager stub for desktop JVM.
*/
public class AppWidgetManager {
public AppWidgetManager() {
}
public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProviders() {
return new java.util.ArrayList<>();
}
public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProvidersForPackage(String packageName, android.os.UserHandle profile) {
return new java.util.ArrayList<>();
}
public android.appwidget.AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
return null;
}
public void updateAppWidget(int appWidgetId, android.widget.RemoteViews views) {
// No-op on desktop
}
public void updateAppWidget(int[] appWidgetIds, android.widget.RemoteViews views) {
// No-op on desktop
}
public void bindAppWidgetIdIfAllowed(int appWidgetId, android.content.ComponentName provider) {
// No-op on desktop
}
}

View File

@@ -0,0 +1,14 @@
package android.bluetooth;
/**
* Minimal BluetoothManager stub for desktop JVM.
*/
public class BluetoothManager {
public BluetoothManager() {
}
public android.bluetooth.BluetoothAdapter getAdapter() {
return null;
}
}

View File

@@ -0,0 +1,311 @@
package android.content;
import android.app.Application;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.os.Looper;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/**
* Concrete Context implementation for the AniyomiBridge application on desktop JVM.
*/
public class ApplicationContext extends Context {
private final Application application;
private final PackageManager packageManager;
private final AssetManager assetManager;
private final Resources resources;
private final ContentResolver contentResolver;
private final File baseDir;
private final File filesDir;
private final File cacheDir;
private final File externalFilesDir;
private final File externalCacheDir;
private final File databaseDir;
private final File sharedPrefsDir;
private final Looper mainLooper;
public ApplicationContext(Application application) {
this.application = application;
this.packageManager = new PackageManager();
this.assetManager = new AssetManager();
this.resources = new Resources();
this.contentResolver = new ContentResolver();
this.mainLooper = Looper.getMainLooper();
// Setup directories
String basePath = System.getProperty("user.home") + File.separator + ".aniyomibridge";
this.baseDir = ensureDir(new File(basePath));
this.filesDir = ensureDir(new File(baseDir, "files"));
this.cacheDir = ensureDir(new File(baseDir, "cache"));
this.externalFilesDir = ensureDir(new File(baseDir, "external_files"));
this.externalCacheDir = ensureDir(new File(baseDir, "external_cache"));
this.databaseDir = ensureDir(new File(baseDir, "databases"));
this.sharedPrefsDir = ensureDir(new File(baseDir, "shared_prefs"));
}
private static File ensureDir(File dir) {
if (!dir.exists()) {
dir.mkdirs();
}
return dir;
}
@Override
public AssetManager getAssets() {
return assetManager;
}
@Override
public Resources getResources() {
return resources;
}
@Override
public PackageManager getPackageManager() {
return packageManager;
}
@Override
public ContentResolver getContentResolver() {
return contentResolver;
}
@Override
public Looper getMainLooper() {
return mainLooper;
}
@Override
public Context getApplicationContext() {
return this;
}
@Override
public void setTheme(int resid) {
// No-op on desktop
}
@Override
public Resources.Theme getTheme() {
return null;
}
@Override
public ClassLoader getClassLoader() {
return Thread.currentThread().getContextClassLoader();
}
@Override
public String getPackageName() {
return "eu.kanade.tachiyomi";
}
@Override
public ApplicationInfo getApplicationInfo() {
ApplicationInfo info = new ApplicationInfo();
info.packageName = getPackageName();
info.targetSdkVersion = 34;
return info;
}
@Override
public String getPackageResourcePath() {
return baseDir.getAbsolutePath();
}
@Override
public String getPackageCodePath() {
return baseDir.getAbsolutePath();
}
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
return application.getSharedPreferences(name, mode);
}
@Override
public boolean moveSharedPreferencesFrom(Context sourceContext, String name) {
return false;
}
@Override
public boolean deleteSharedPreferences(String name) {
File prefsFile = new File(sharedPrefsDir, name + ".xml");
return prefsFile.delete();
}
@Override
public FileInputStream openFileInput(String name) throws FileNotFoundException {
return new FileInputStream(new File(filesDir, name));
}
@Override
public FileOutputStream openFileOutput(String name, int mode) throws FileNotFoundException {
File file = new File(filesDir, name);
if ((mode & MODE_APPEND) == 0) {
// Truncate mode - delete existing file
file.delete();
}
return new FileOutputStream(file, (mode & MODE_APPEND) != 0);
}
@Override
public boolean deleteFile(String name) {
return new File(filesDir, name).delete();
}
@Override
public File getFileStreamPath(String name) {
return new File(filesDir, name);
}
@Override
public File getDataDir() {
return baseDir;
}
@Override
public File getFilesDir() {
return filesDir;
}
@Override
public File getNoBackupFilesDir() {
return filesDir;
}
@Override
public File getExternalFilesDir(String type) {
if (type != null) {
return ensureDir(new File(externalFilesDir, type));
}
return externalFilesDir;
}
@Override
public File[] getExternalFilesDirs(String type) {
return new File[] { getExternalFilesDir(type) };
}
@Override
public File getObbDir() {
return ensureDir(new File(baseDir, "obb"));
}
@Override
public File[] getObbDirs() {
return new File[] { getObbDir() };
}
@Override
public File getCacheDir() {
return cacheDir;
}
@Override
public File getCodeCacheDir() {
return cacheDir;
}
@Override
public File getExternalCacheDir() {
return externalCacheDir;
}
@Override
public File[] getExternalCacheDirs() {
return new File[] { externalCacheDir };
}
@Override
public File[] getExternalMediaDirs() {
return new File[0];
}
@Override
public String[] fileList() {
return filesDir.list();
}
@Override
public File getDir(String name, int mode) {
return ensureDir(new File(filesDir, name));
}
@Override
public File getSharedPreferencesPath(String name) {
return new File(sharedPrefsDir, name + ".xml");
}
@Override
public File getDatabasePath(String name) {
return new File(databaseDir, name);
}
@Override
public boolean moveDatabaseFrom(Context sourceContext, String name) {
return false;
}
@Override
public boolean deleteDatabase(String name) {
return new File(databaseDir, name).delete();
}
@Override
public String[] databaseList() {
return databaseDir.list();
}
@Override
public Object getSystemService(String name) {
if (name == null) {
return null;
}
return switch (name) {
case CONNECTIVITY_SERVICE -> new ConnectivityManager();
case WINDOW_SERVICE -> new android.view.WindowManager();
case ACTIVITY_SERVICE -> new android.app.ActivityManager();
case POWER_SERVICE -> new android.os.PowerManager();
case ALARM_SERVICE -> new android.app.AlarmManager();
case NOTIFICATION_SERVICE -> new android.app.NotificationManager();
case LOCATION_SERVICE -> new android.location.LocationManager();
case TELEPHONY_SERVICE -> new android.telephony.TelephonyManager();
case AUDIO_SERVICE -> new android.media.AudioManager();
case CLIPBOARD_SERVICE -> new ClipboardManager();
case INPUT_METHOD_SERVICE -> new android.view.inputmethod.InputMethodManager();
case SEARCH_SERVICE -> new android.app.SearchManager();
case STORAGE_SERVICE -> new android.os.storage.StorageManager();
case WIFI_SERVICE -> new android.net.wifi.WifiManager();
case DISPLAY_SERVICE -> new android.hardware.display.DisplayManager();
case SENSOR_SERVICE -> new android.hardware.SensorManager();
case LAYOUT_INFLATER_SERVICE -> new android.view.LayoutInflater();
case KEYGUARD_SERVICE -> new android.app.KeyguardManager();
case VIBRATOR_SERVICE -> new android.os.Vibrator();
case UI_MODE_SERVICE -> new android.app.UiModeManager();
case DEVICE_POLICY_SERVICE -> new android.app.admin.DevicePolicyManager();
case DOWNLOAD_SERVICE -> new android.app.DownloadManager();
case BATTERY_SERVICE -> new android.os.BatteryManager();
case BLUETOOTH_SERVICE -> new android.bluetooth.BluetoothManager();
case JOB_SCHEDULER_SERVICE -> new android.app.job.JobScheduler();
case ACCESSIBILITY_SERVICE -> new android.view.accessibility.AccessibilityManager();
case ACCOUNT_SERVICE -> new android.accounts.AccountManager();
case APPWIDGET_SERVICE -> new android.appwidget.AppWidgetManager();
case NFC_SERVICE -> new android.nfc.NfcManager();
case WIFI_P2P_SERVICE -> new android.net.wifi.p2p.WifiP2pManager();
case SHORTCUT_SERVICE -> new android.content.pm.ShortcutManager();
default -> {
System.err.println("WARNING: Unimplemented system service requested: " + name);
yield null;
}
};
}
}

View File

@@ -0,0 +1,50 @@
package android.content;
/**
* Minimal ClipboardManager stub for desktop JVM.
*/
public class ClipboardManager {
public ClipboardManager() {
}
public void setText(CharSequence text) {
// No-op on desktop
}
public CharSequence getText() {
return "";
}
public boolean hasText() {
return false;
}
public void setPrimaryClip(android.content.ClipData clip) {
// No-op on desktop
}
public android.content.ClipData getPrimaryClip() {
return null;
}
public android.content.ClipDescription getPrimaryClipDescription() {
return null;
}
public boolean hasPrimaryClip() {
return false;
}
public void addPrimaryClipChangedListener(android.content.ClipboardManager.OnPrimaryClipChangedListener what) {
// No-op on desktop
}
public void removePrimaryClipChangedListener(android.content.ClipboardManager.OnPrimaryClipChangedListener what) {
// No-op on desktop
}
public interface OnPrimaryClipChangedListener {
void onPrimaryClipChanged();
}
}

View File

@@ -0,0 +1,123 @@
package android.content;
/**
* Minimal ContentResolver stub for desktop JVM.
*/
public class ContentResolver {
public static final String SYNC_EXTRAS_ACCOUNT = "account";
public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
public static final String SYNC_EXTRAS_FORCE = "force";
public static final String SYNC_EXTRAS_UPLOAD = "upload";
public static final String SYNC_EXTRAS_MANUAL = "force";
public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
public static final String SYNC_EXTRAS_EXPECTED_UPLOAD = "expected_upload";
public static final String SYNC_EXTRAS_EXPECTED_DOWNLOAD = "expected_download";
public static final String SYNC_EXTRAS_PRIORITY = "priority";
public static final String SCHEME_CONTENT = "content";
public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
public static final String SCHEME_FILE = "file";
public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
public static final int SYNC_ERROR_AUTHENTICATION = 2;
public static final int SYNC_ERROR_IO = 3;
public static final int SYNC_ERROR_PARSE = 4;
public static final int SYNC_ERROR_CONFLICT = 5;
public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6;
public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7;
public static final int SYNC_ERROR_INTERNAL = 8;
public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1;
public static final int SYNC_OBSERVER_TYPE_PENDING = 2;
public static final int SYNC_OBSERVER_TYPE_ACTIVE = 4;
public ContentResolver() {
}
public final String getType(android.net.Uri uri) {
return null;
}
public String[] getStreamTypes(android.net.Uri uri, String mimeTypeFilter) {
return null;
}
public final android.database.Cursor query(android.net.Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return null;
}
public final android.database.Cursor query(android.net.Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, android.os.CancellationSignal cancellationSignal) {
return null;
}
public final android.database.Cursor query(android.net.Uri uri, String[] projection, android.os.Bundle queryArgs, android.os.CancellationSignal cancellationSignal) {
return null;
}
public final android.net.Uri insert(android.net.Uri uri, android.content.ContentValues values) {
return null;
}
public final int bulkInsert(android.net.Uri uri, android.content.ContentValues[] valuesArray) {
return 0;
}
public final int delete(android.net.Uri uri, String selection, String[] selectionArgs) {
return 0;
}
public final int update(android.net.Uri uri, android.content.ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
public final android.os.ParcelFileDescriptor openFileDescriptor(android.net.Uri uri, String mode) throws java.io.FileNotFoundException {
return null;
}
public final java.io.InputStream openInputStream(android.net.Uri uri) throws java.io.FileNotFoundException {
return null;
}
public final java.io.OutputStream openOutputStream(android.net.Uri uri) throws java.io.FileNotFoundException {
return null;
}
public final java.io.OutputStream openOutputStream(android.net.Uri uri, String mode) throws java.io.FileNotFoundException {
return null;
}
public final void registerContentObserver(android.net.Uri uri, boolean notifyForDescendants, android.database.ContentObserver observer) {
// No-op on desktop
}
public final void unregisterContentObserver(android.database.ContentObserver observer) {
// No-op on desktop
}
public void notifyChange(android.net.Uri uri, android.database.ContentObserver observer) {
// No-op on desktop
}
public void notifyChange(android.net.Uri uri, android.database.ContentObserver observer, boolean syncToNetwork) {
// No-op on desktop
}
public void takePersistableUriPermission(android.net.Uri uri, int modeFlags) {
// No-op on desktop
}
public void releasePersistableUriPermission(android.net.Uri uri, int modeFlags) {
// No-op on desktop
}
public java.util.List<android.content.UriPermission> getPersistedUriPermissions() {
return new java.util.ArrayList<>();
}
public static void requestSync(android.accounts.Account account, String authority, android.os.Bundle extras) {
// No-op on desktop
}
public static void cancelSync(android.accounts.Account account, String authority) {
// No-op on desktop
}
}

View File

@@ -1,12 +1,479 @@
package android.content;
import java.io.File;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Display;
public class Context {
public static final int MODE_PRIVATE = 0;
public static File getCacheDir() {
return new File(System.getProperty("java.io.tmpdir"));
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/**
* Abstract Context implementation for desktop JVM.
* <p>
* This is a stub implementation that provides sensible defaults for most methods.
* Methods that don't make sense on desktop (like startActivity) log a warning.
*/
public abstract class Context {
// File creation modes
public static final int MODE_PRIVATE = 0x0000;
@Deprecated
public static final int MODE_WORLD_READABLE = 0x0001;
@Deprecated
public static final int MODE_WORLD_WRITEABLE = 0x0002;
public static final int MODE_APPEND = 0x8000;
public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 0x0008;
public static final int MODE_NO_LOCALIZED_COLLATORS = 0x0010;
public static final int MODE_MULTI_PROCESS = 0x0004;
// Service names
public static final String CONNECTIVITY_SERVICE = "connectivity";
public static final String WINDOW_SERVICE = "window";
public static final String ACTIVITY_SERVICE = "activity";
public static final String POWER_SERVICE = "power";
public static final String ALARM_SERVICE = "alarm";
public static final String NOTIFICATION_SERVICE = "notification";
public static final String LOCATION_SERVICE = "location";
public static final String TELEPHONY_SERVICE = "phone";
public static final String AUDIO_SERVICE = "audio";
public static final String CLIPBOARD_SERVICE = "clipboard";
public static final String INPUT_METHOD_SERVICE = "input_method";
public static final String SEARCH_SERVICE = "search";
public static final String STORAGE_SERVICE = "storage";
public static final String WIFI_SERVICE = "wifi";
public static final String DISPLAY_SERVICE = "display";
public static final String SENSOR_SERVICE = "sensor";
public static final String CAMERA_SERVICE = "camera";
public static final String KEYGUARD_SERVICE = "keyguard";
public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
public static final String VIBRATOR_SERVICE = "vibrator";
public static final String UI_MODE_SERVICE = "uimode";
public static final String DEVICE_POLICY_SERVICE = "device_policy";
public static final String DOWNLOAD_SERVICE = "download";
public static final String BATTERY_SERVICE = "batterymanager";
public static final String JOB_SCHEDULER_SERVICE = "jobscheduler";
public static final String ACCESSIBILITY_SERVICE = "accessibility";
public static final String ACCOUNT_SERVICE = "account";
public static final String APPWIDGET_SERVICE = "appwidget";
public static final String BLUETOOTH_SERVICE = "bluetooth";
public static final String DROPBOX_SERVICE = "dropbox";
public static final String MEDIA_ROUTER_SERVICE = "media_router";
public static final String NFC_SERVICE = "nfc";
public static final String PRINT_SERVICE = "print";
public static final String RESTRICTIONS_SERVICE = "restrictions";
public static final String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
public static final String TELECOM_SERVICE = "telecom";
public static final String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
public static final String TV_INPUT_SERVICE = "tv_input";
public static final String USAGE_STATS_SERVICE = "usagestats";
public static final String USB_SERVICE = "usb";
public static final String USER_SERVICE = "user";
public static final String WALLPAPER_SERVICE = "wallpaper";
public static final String SHORTCUT_SERVICE = "shortcut";
public static final String COMPANION_DEVICE_SERVICE = "companiondevice";
public static final String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps";
public static final String SLICE_SERVICE = "slice";
public static final String TIME_ZONE_RULES_MANAGER_SERVICE = "timezone";
public static final String APP_PREDICTION_SERVICE = "app_prediction";
public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
public static final String TRANSLATION_MANAGER_SERVICE = "translation";
public static final String BLOB_STORE_SERVICE = "blob_store";
public static final String FILE_INTEGRITY_SERVICE = "file_integrity";
public static final String APP_OPS_SERVICE = "appops";
public static final String ROLLBACK_SERVICE = "rollback";
public static final String DYNAMIC_SYSTEM_SERVICE = "dynamic_system";
public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification";
public static final String GAME_SERVICE = "game";
public static final String LOCALE_SERVICE = "locale";
public static final String MUSIC_RECOGNITION_SERVICE = "music_recognition";
public static final String PEOPLE_SERVICE = "people";
public static final String PERFORMANCE_HINT_SERVICE = "performance_hint";
public static final String SAFETY_CENTER_SERVICE = "safety_center";
public static final String CREDENTIAL_SERVICE = "credential";
public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
public static final String UWB_SERVICE = "uwb";
public static final String WIFI_AWARE_SERVICE = "wifiaware";
public static final String WIFI_P2P_SERVICE = "wifip2p";
public static final String WIFI_RTT_RANGING_SERVICE = "wifirtt";
public static final String CARRIER_CONFIG_SERVICE = "carrier_config";
public static final String EUICC_SERVICE = "euicc";
public static final String IPSEC_SERVICE = "ipsec";
public static final String MEDIA_SESSION_SERVICE = "media_session";
public static final String NETWORK_STATS_SERVICE = "netstats";
public static final String NETWORK_POLICY_SERVICE = "netpolicy";
public static final String NETWORK_SCORE_SERVICE = "network_score";
public static final String OEM_LOCK_SERVICE = "oem_lock";
public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
public static final String RECOVERY_SERVICE = "recovery";
public static final String SERVICE_DISCOVERY_SERVICE = "servicediscovery";
public static final String SOUND_TRIGGER_SERVICE = "soundtrigger";
public static final String STATS_MANAGER_SERVICE = "stats";
public static final String STORAGE_STATS_SERVICE = "storagestats";
public static final String TRUST_SERVICE = "trust";
public static final String VIRTUALIZATION_SERVICE = "virtualization";
private static final String BASE_DIR = System.getProperty("user.home") + File.separator + ".aniyomibridge";
// ==================== ABSTRACT METHODS ====================
public abstract AssetManager getAssets();
public abstract Resources getResources();
public abstract PackageManager getPackageManager();
public abstract ContentResolver getContentResolver();
public abstract Looper getMainLooper();
public abstract Context getApplicationContext();
public abstract void setTheme(int resid);
public abstract Resources.Theme getTheme();
public abstract ClassLoader getClassLoader();
public abstract String getPackageName();
public abstract ApplicationInfo getApplicationInfo();
public abstract String getPackageResourcePath();
public abstract String getPackageCodePath();
public abstract SharedPreferences getSharedPreferences(String name, int mode);
public abstract boolean moveSharedPreferencesFrom(Context sourceContext, String name);
public abstract boolean deleteSharedPreferences(String name);
public abstract FileInputStream openFileInput(String name) throws FileNotFoundException;
public abstract FileOutputStream openFileOutput(String name, int mode) throws FileNotFoundException;
public abstract boolean deleteFile(String name);
public abstract File getFileStreamPath(String name);
public abstract File getDataDir();
public abstract File getFilesDir();
public abstract File getNoBackupFilesDir();
public abstract File getExternalFilesDir(String type);
public abstract File[] getExternalFilesDirs(String type);
public abstract File getObbDir();
public abstract File[] getObbDirs();
public abstract File getCacheDir();
public abstract File getCodeCacheDir();
public abstract File getExternalCacheDir();
public abstract File[] getExternalCacheDirs();
public abstract File[] getExternalMediaDirs();
public abstract String[] fileList();
public abstract File getDir(String name, int mode);
public abstract Object getSystemService(String name);
// ==================== CONCRETE METHODS WITH DEFAULTS ====================
public static File getCacheDirStatic() {
return new File(BASE_DIR, "cache");
}
public Context() {
public File getSharedPreferencesPath(String name) {
return new File(getFilesDir(), name + ".xml");
}
public File getDatabasePath(String name) {
return new File(getFilesDir(), name);
}
public boolean moveDatabaseFrom(Context sourceContext, String name) {
return false;
}
public boolean deleteDatabase(String name) {
return new File(getFilesDir(), name).delete();
}
public String[] databaseList() {
return getFilesDir().list();
}
public void registerComponentCallbacks(android.content.ComponentCallbacks callback) {
// No-op on desktop
}
public void unregisterComponentCallbacks(android.content.ComponentCallbacks callback) {
// No-op on desktop
}
// Activity/Intent methods (no-op on desktop)
public void startActivity(android.content.Intent intent) {
System.err.println("WARNING: Context.startActivity() called on desktop - not supported");
}
public void startActivity(android.content.Intent intent, Bundle options) {
startActivity(intent);
}
public void startActivities(android.content.Intent[] intents) {
for (android.content.Intent intent : intents) {
startActivity(intent);
}
}
public void startActivities(android.content.Intent[] intents, Bundle options) {
startActivities(intents);
}
public void sendBroadcast(android.content.Intent intent) {
// No-op on desktop
}
public void sendBroadcast(android.content.Intent intent, String receiverPermission) {
sendBroadcast(intent);
}
public void sendOrderedBroadcast(android.content.Intent intent, String receiverPermission) {
sendBroadcast(intent);
}
public void sendStickyBroadcast(android.content.Intent intent) {
sendBroadcast(intent);
}
public void removeStickyBroadcast(android.content.Intent intent) {
// No-op
}
public android.content.Intent registerReceiver(android.content.BroadcastReceiver receiver, android.content.IntentFilter filter) {
// No-op on desktop
return null;
}
public android.content.Intent registerReceiver(android.content.BroadcastReceiver receiver, android.content.IntentFilter filter, int flags) {
return registerReceiver(receiver, filter);
}
public android.content.Intent registerReceiver(android.content.BroadcastReceiver receiver, android.content.IntentFilter filter, String broadcastPermission, Handler scheduler) {
return registerReceiver(receiver, filter);
}
public android.content.Intent registerReceiver(android.content.BroadcastReceiver receiver, android.content.IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
return registerReceiver(receiver, filter);
}
public void unregisterReceiver(android.content.BroadcastReceiver receiver) {
// No-op on desktop
}
public android.content.ComponentName startService(android.content.Intent service) {
System.err.println("WARNING: Context.startService() called on desktop - not supported");
return null;
}
public boolean stopService(android.content.Intent name) {
return false;
}
public boolean bindService(android.content.Intent service, android.content.ServiceConnection conn, int flags) {
System.err.println("WARNING: Context.bindService() called on desktop - not supported");
return false;
}
public void unbindService(android.content.ServiceConnection conn) {
// No-op on desktop
}
// Permission methods (grant everything on desktop)
public int checkPermission(String permission, int pid, int uid) {
return android.content.pm.PackageManager.PERMISSION_GRANTED;
}
public int checkCallingPermission(String permission) {
return android.content.pm.PackageManager.PERMISSION_GRANTED;
}
public int checkCallingOrSelfPermission(String permission) {
return android.content.pm.PackageManager.PERMISSION_GRANTED;
}
public int checkSelfPermission(String permission) {
return android.content.pm.PackageManager.PERMISSION_GRANTED;
}
public void enforcePermission(String permission, int pid, int uid, String message) {
// Always granted on desktop
}
public void enforceCallingPermission(String permission, String message) {
// Always granted on desktop
}
public void enforceCallingOrSelfPermission(String permission, String message) {
// Always granted on desktop
}
// URI permission methods
public int checkUriPermission(android.net.Uri uri, int pid, int uid, int modeFlags) {
return android.content.pm.PackageManager.PERMISSION_GRANTED;
}
public int checkCallingUriPermission(android.net.Uri uri, int modeFlags) {
return android.content.pm.PackageManager.PERMISSION_GRANTED;
}
public int checkCallingOrSelfUriPermission(android.net.Uri uri, int modeFlags) {
return android.content.pm.PackageManager.PERMISSION_GRANTED;
}
public void enforceUriPermission(android.net.Uri uri, int pid, int uid, int modeFlags, String message) {
// Always granted
}
public void enforceCallingUriPermission(android.net.Uri uri, int modeFlags, String message) {
// Always granted
}
public void enforceCallingOrSelfUriPermission(android.net.Uri uri, int modeFlags, String message) {
// Always granted
}
public void grantUriPermission(String toPackage, android.net.Uri uri, int modeFlags) {
// No-op
}
public void revokeUriPermission(android.net.Uri uri, int modeFlags) {
// No-op
}
public void revokeUriPermission(String toPackage, android.net.Uri uri, int modeFlags) {
// No-op
}
// Resource convenience methods
public final CharSequence getText(int resId) {
return "";
}
public final String getString(int resId) {
return "";
}
public final String getString(int resId, Object... formatArgs) {
return String.format(getString(resId), formatArgs);
}
public final int getColor(int id) {
return 0;
}
public final android.graphics.drawable.Drawable getDrawable(int id) {
return null;
}
public final android.content.res.ColorStateList getColorStateList(int id) {
return null;
}
// Theme methods
public final android.content.res.TypedArray obtainStyledAttributes(int[] attrs) {
return null;
}
public final android.content.res.TypedArray obtainStyledAttributes(int resid, int[] attrs) throws android.content.res.Resources.NotFoundException {
return null;
}
public final android.content.res.TypedArray obtainStyledAttributes(android.util.AttributeSet set, int[] attrs) {
return null;
}
public final android.content.res.TypedArray obtainStyledAttributes(android.util.AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
return null;
}
// Context creation methods
public Context createPackageContext(String packageName, int flags) throws android.content.pm.PackageManager.NameNotFoundException {
return this;
}
public Context createConfigurationContext(android.content.res.Configuration overrideConfiguration) {
return this;
}
public Context createDisplayContext(Display display) {
return this;
}
public Context createDeviceProtectedStorageContext() {
return this;
}
public Context createCredentialProtectedStorageContext() {
return this;
}
public Context createAttributionContext(String attributionTag) {
return this;
}
public boolean isDeviceProtectedStorage() {
return false;
}
public boolean isCredentialProtectedStorage() {
return false;
}
public boolean canLoadUnsafeResources() {
return false;
}
// Other methods
public String getOpPackageName() {
return getPackageName();
}
public String getAttributionTag() {
return null;
}
public android.content.AttributionSource getAttributionSource() {
return null;
}
public boolean isRestricted() {
return false;
}
public android.content.Context getBaseContext() {
return this;
}
public int getUserId() {
return 0;
}
public String getSystemServiceName(Class<?> serviceClass) {
return null;
}
public int getDisplayId() {
return 0;
}
public Display getDisplay() {
return null;
}
public void updateDisplay(int displayId) {
// No-op
}
public void registerDeviceIdChangeListener(java.util.concurrent.Executor executor, java.util.function.IntConsumer listener) {
// No-op
}
public void unregisterDeviceIdChangeListener(java.util.function.IntConsumer listener) {
// No-op
}
public int getDeviceId() {
return 0;
}
public boolean isUiContext() {
return false;
}
public android.view.WindowManager getSystemService(java.lang.Class<android.view.WindowManager> serviceClass) {
return (android.view.WindowManager) getSystemService(WINDOW_SERVICE);
}
}

View File

@@ -1,24 +1,55 @@
package android.content;
import java.util.Map;
import java.util.Set;
public interface SharedPreferences {
boolean getBoolean(String key, boolean defaultValue);
void putBoolean(String key, boolean value);
Map<String, ?> getAll();
String getString(String key, String defaultValue);
Set<String> getStringSet(String key, Set<String> defaultValue);
void putStringSet(String key, Set<String> value);
void putString(String key, String value);
void remove(String key);
String get(String key, String defaultValue);
int getInt(String key, int defaultValue);
long getLong(String key, long defaultValue);
float getFloat(String key, float defaultValue);
boolean getBoolean(String key, boolean defaultValue);
boolean contains(String key);
Editor edit();
void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
interface Editor {
Editor putBoolean(String key, boolean value);
Editor putString(String key, String value);
Editor putStringSet(String key, Set<String> value);
Editor putStringSet(String key, Set<String> values);
Editor putInt(String key, int value);
Editor putLong(String key, long value);
Editor putFloat(String key, float value);
Editor putBoolean(String key, boolean value);
Editor remove(String key);
Editor clear();
boolean commit();
void apply();
}
interface OnSharedPreferenceChangeListener {
void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
}
}

View File

@@ -1,5 +1,11 @@
package android.content;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.prefs.Preferences;
@@ -7,19 +13,49 @@ public class SharedPreferencesImpl implements SharedPreferences {
private final Preferences prefs;
private final Editor editor = new EditorImpl(this);
private final Set<OnSharedPreferenceChangeListener> listeners = new HashSet<>();
private final Gson gson = new Gson();
public SharedPreferencesImpl(String key) {
prefs = Preferences.userRoot().node(key);
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
return prefs.getBoolean(key, defaultValue);
public Map<String, ?> getAll() {
Map<String, Object> result = new HashMap<>();
try {
for (String key : prefs.keys()) {
String value = prefs.get(key, null);
if (value != null) {
// Try to parse as typed values
result.put(key, parseValue(value));
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
@Override
public void putBoolean(String key, boolean value) {
prefs.putBoolean(key, value);
private Object parseValue(String value) {
// Try boolean
if ("true".equals(value) || "false".equals(value)) {
return Boolean.parseBoolean(value);
}
// Try int
try {
return Integer.parseInt(value);
} catch (NumberFormatException ignored) {}
// Try long
try {
return Long.parseLong(value);
} catch (NumberFormatException ignored) {}
// Try float
try {
return Float.parseFloat(value);
} catch (NumberFormatException ignored) {}
// Default to string
return value;
}
@Override
@@ -29,34 +65,59 @@ public class SharedPreferencesImpl implements SharedPreferences {
@Override
public Set<String> getStringSet(String key, Set<String> defaultValue) {
if (defaultValue != null) {
return Set.of(prefs.get(key, String.join(";", defaultValue)).split(";"));
String json = prefs.get(key, null);
if (json == null) {
return defaultValue;
}
try {
return gson.fromJson(json, new TypeToken<Set<String>>(){}.getType());
} catch (Exception e) {
// Fallback: try old semicolon-delimited format
try {
Set<String> result = new HashSet<>();
for (String s : json.split(";")) {
if (!s.isEmpty()) {
result.add(s);
}
}
return result;
} catch (Exception e2) {
return defaultValue;
}
}
}
@Override
public int getInt(String key, int defaultValue) {
return prefs.getInt(key, defaultValue);
}
@Override
public long getLong(String key, long defaultValue) {
return prefs.getLong(key, defaultValue);
}
@Override
public float getFloat(String key, float defaultValue) {
String value = prefs.get(key, null);
if (value != null) {
return Set.of(value.split(";"));
if (value == null) {
return defaultValue;
}
try {
return Float.parseFloat(value);
} catch (NumberFormatException e) {
return defaultValue;
}
return null;
}
@Override
public void putStringSet(String key, Set<String> value) {
prefs.put(key, String.join(";", value));
public boolean getBoolean(String key, boolean defaultValue) {
return prefs.getBoolean(key, defaultValue);
}
@Override
public void putString(String key, String value) {
prefs.put(key, value);
}
@Override
public void remove(String key) {
prefs.remove(key);
}
@Override
public String get(String key, String defaultValue) {
return prefs.get(key, defaultValue);
public boolean contains(String key) {
return prefs.get(key, null) != null;
}
@Override
@@ -64,45 +125,129 @@ public class SharedPreferencesImpl implements SharedPreferences {
return editor;
}
private static class EditorImpl implements SharedPreferences.Editor {
@Override
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
listeners.add(listener);
}
@Override
public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
listeners.remove(listener);
}
void notifyListeners(String key) {
for (OnSharedPreferenceChangeListener listener : new HashSet<>(listeners)) {
try {
listener.onSharedPreferenceChanged(this, key);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static class EditorImpl implements Editor {
private final SharedPreferencesImpl prefs;
private final Map<String, Object> pendingChanges = new HashMap<>();
private boolean clear = false;
public EditorImpl(SharedPreferencesImpl prefs) {
this.prefs = prefs;
}
@Override
public Editor putBoolean(String key, boolean value) {
prefs.putBoolean(key, value);
return this;
}
@Override
public Editor putString(String key, String value) {
prefs.putString(key, value);
pendingChanges.put(key, value);
return this;
}
@Override
public Editor putStringSet(String key, Set<String> value) {
prefs.putStringSet(key, value);
public Editor putStringSet(String key, Set<String> values) {
pendingChanges.put(key, values);
return this;
}
@Override
public Editor putInt(String key, int value) {
pendingChanges.put(key, value);
return this;
}
@Override
public Editor putLong(String key, long value) {
pendingChanges.put(key, value);
return this;
}
@Override
public Editor putFloat(String key, float value) {
pendingChanges.put(key, value);
return this;
}
@Override
public Editor putBoolean(String key, boolean value) {
pendingChanges.put(key, value);
return this;
}
@Override
public Editor remove(String key) {
prefs.remove(key);
pendingChanges.put(key, null); // null means remove
return this;
}
@Override
public Editor clear() {
clear = true;
pendingChanges.clear();
return this;
}
@Override
public boolean commit() {
apply();
return true;
}
@Override
public void apply() {
if (clear) {
try {
for (String key : prefs.prefs.keys()) {
prefs.prefs.remove(key);
}
} catch (Exception e) {
e.printStackTrace();
}
}
for (Map.Entry<String, Object> entry : pendingChanges.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (value == null) {
prefs.prefs.remove(key);
} else if (value instanceof String) {
prefs.prefs.put(key, (String) value);
} else if (value instanceof Set) {
// Store as JSON array
prefs.prefs.put(key, prefs.gson.toJson(value));
} else if (value instanceof Integer) {
prefs.prefs.putInt(key, (Integer) value);
} else if (value instanceof Long) {
prefs.prefs.putLong(key, (Long) value);
} else if (value instanceof Float) {
prefs.prefs.put(key, value.toString());
} else if (value instanceof Boolean) {
prefs.prefs.putBoolean(key, (Boolean) value);
}
prefs.notifyListeners(key);
}
pendingChanges.clear();
clear = false;
}
}
}

View File

@@ -0,0 +1,236 @@
package android.content.pm;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import java.util.ArrayList;
import java.util.List;
/**
* Minimal PackageManager stub for desktop JVM.
*/
public class PackageManager {
public static final int GET_ACTIVITIES = 0x00000001;
public static final int GET_CONFIGURATIONS = 0x00004000;
public static final int GET_GIDS = 0x00000100;
public static final int GET_INSTRUMENTATION = 0x00000010;
public static final int GET_INTENT_FILTERS = 0x00000020;
public static final int GET_META_DATA = 0x00000080;
public static final int GET_PERMISSIONS = 0x00001000;
public static final int GET_PROVIDERS = 0x00000008;
public static final int GET_RECEIVERS = 0x00000002;
public static final int GET_RESOLVED_FILTER = 0x00000040;
public static final int GET_SERVICES = 0x00000004;
public static final int GET_SHARED_LIBRARY_FILES = 0x00000400;
public static final int GET_SIGNATURES = 0x00000040;
public static final int GET_SIGNING_CERTIFICATES = 0x08000000;
public static final int GET_URI_PERMISSION_PATTERNS = 0x00000800;
public static final int MATCH_ALL = 0x00020000;
public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x00010000;
public static final int MATCH_DEFAULT_ONLY = 0x00010000;
public static final int MATCH_DIRECT_BOOT_AWARE = 0x00040000;
public static final int MATCH_DIRECT_BOOT_UNAWARE = 0x00080000;
public static final int MATCH_DISABLED_COMPONENTS = 0x00020000;
public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 0x00080000;
public static final int MATCH_EXPLICITLY_ONLY = 0x00100000;
public static final int MATCH_FACTORY_ONLY = 0x00200000;
public static final int MATCH_SYSTEM_ONLY = 0x00040000;
public static final int MATCH_UNINSTALLED_PACKAGES = 0x00002000;
public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0;
public static final int COMPONENT_ENABLED_STATE_ENABLED = 1;
public static final int COMPONENT_ENABLED_STATE_DISABLED = 2;
public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3;
public static final int COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4;
public static final int PERMISSION_GRANTED = 0;
public static final int PERMISSION_DENIED = -1;
public static final int SIGNATURE_MATCH = 0;
public static final int SIGNATURE_NEITHER_SIGNED = 1;
public static final int SIGNATURE_FIRST_NOT_SIGNED = -1;
public static final int SIGNATURE_SECOND_NOT_SIGNED = -2;
public static final int SIGNATURE_NO_MATCH = -3;
public static final int SIGNATURE_UNKNOWN_PACKAGE = -4;
public PackageManager() {
}
public PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException {
PackageInfo info = new PackageInfo();
info.packageName = packageName;
return info;
}
public ApplicationInfo getApplicationInfo(String packageName, int flags) throws NameNotFoundException {
ApplicationInfo info = new ApplicationInfo();
info.packageName = packageName;
return info;
}
public ActivityInfo getActivityInfo(android.content.ComponentName component, int flags) throws NameNotFoundException {
ActivityInfo info = new ActivityInfo();
info.packageName = component.getPackageName();
info.name = component.getClassName();
return info;
}
public ServiceInfo getServiceInfo(android.content.ComponentName component, int flags) throws NameNotFoundException {
ServiceInfo info = new ServiceInfo();
info.packageName = component.getPackageName();
info.name = component.getClassName();
return info;
}
public ProviderInfo getProviderInfo(android.content.ComponentName component, int flags) throws NameNotFoundException {
ProviderInfo info = new ProviderInfo();
info.packageName = component.getPackageName();
info.name = component.getClassName();
return info;
}
public List<PackageInfo> getInstalledPackages(int flags) {
return new ArrayList<>();
}
public List<ApplicationInfo> getInstalledApplications(int flags) {
return new ArrayList<>();
}
public int checkPermission(String permName, String pkgName) {
return PERMISSION_GRANTED;
}
public boolean addPermission(PermissionInfo info) {
return false;
}
public boolean addPermissionAsync(PermissionInfo info) {
return false;
}
public void removePermission(String name) {
}
public int checkSignatures(String pkg1, String pkg2) {
return SIGNATURE_MATCH;
}
public int checkSignatures(int uid1, int uid2) {
return SIGNATURE_MATCH;
}
public String[] getPackagesForUid(int uid) {
return new String[0];
}
public String getNameForUid(int uid) {
return null;
}
public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
return new ArrayList<>();
}
public List<ResolveInfo> queryIntentActivityOptions(android.content.ComponentName caller, Intent[] specifics, Intent intent, int flags) {
return new ArrayList<>();
}
public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
return new ArrayList<>();
}
public ResolveInfo resolveService(Intent intent, int flags) {
return null;
}
public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
return new ArrayList<>();
}
public List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags) {
return new ArrayList<>();
}
public ResolveInfo resolveActivity(Intent intent, int flags) {
return null;
}
public ProviderInfo resolveContentProvider(String name, int flags) {
return null;
}
public Drawable getApplicationIcon(ApplicationInfo info) {
return null;
}
public Drawable getApplicationIcon(String packageName) throws NameNotFoundException {
return null;
}
public Drawable getActivityIcon(android.content.ComponentName activityName) throws NameNotFoundException {
return null;
}
public Drawable getActivityIcon(Intent intent) throws NameNotFoundException {
return null;
}
public Drawable getDefaultActivityIcon() {
return null;
}
public Resources getResourcesForActivity(android.content.ComponentName activityName) throws NameNotFoundException {
return new Resources();
}
public Resources getResourcesForApplication(ApplicationInfo app) throws NameNotFoundException {
return new Resources();
}
public Resources getResourcesForApplication(String appPackageName) throws NameNotFoundException {
return new Resources();
}
public CharSequence getText(String packageName, int resid, ApplicationInfo appInfo) {
return "";
}
public CharSequence getApplicationLabel(ApplicationInfo info) {
return info.packageName;
}
public android.content.pm.PackageInstaller getPackageInstaller() {
return null;
}
public boolean isInstantApp() {
return false;
}
public boolean isInstantApp(String packageName) {
return false;
}
public int getInstantAppCookieMaxBytes() {
return 0;
}
public byte[] getInstantAppCookie() {
return new byte[0];
}
public boolean setInstantAppCookie(byte[] cookie) {
return false;
}
public void clearInstantAppCookie() {
}
public static class NameNotFoundException extends android.util.AndroidException {
public NameNotFoundException() {
}
public NameNotFoundException(String name) {
super(name);
}
}
}

View File

@@ -0,0 +1,70 @@
package android.content.pm;
/**
* Minimal ShortcutManager stub for desktop JVM.
*/
public class ShortcutManager {
public ShortcutManager() {
}
public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo> shortcutInfoList) {
return false;
}
public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts() {
return new java.util.ArrayList<>();
}
public java.util.List<android.content.pm.ShortcutInfo> getManifestShortcuts() {
return new java.util.ArrayList<>();
}
public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo> shortcutInfoList) {
return false;
}
public void removeDynamicShortcuts(java.util.List<String> shortcutIds) {
// No-op on desktop
}
public void removeAllDynamicShortcuts() {
// No-op on desktop
}
public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts() {
return new java.util.ArrayList<>();
}
public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo> shortcutInfoList) {
return false;
}
public void disableShortcuts(java.util.List<String> shortcutIds) {
// No-op on desktop
}
public void enableShortcuts(java.util.List<String> shortcutIds) {
// No-op on desktop
}
public int getMaxShortcutCountPerActivity() {
return 0;
}
public boolean isRateLimitingActive() {
return false;
}
public int getIconMaxWidth() {
return 0;
}
public int getIconMaxHeight() {
return 0;
}
public void reportShortcutUsed(String shortcutId) {
// No-op on desktop
}
}

View File

@@ -0,0 +1,26 @@
package android.content.res;
/**
* Minimal AssetManager stub for desktop JVM.
*/
public class AssetManager {
public AssetManager() {
}
public String[] list(String path) {
return new String[0];
}
public java.io.InputStream open(String fileName) throws java.io.IOException {
return new java.io.ByteArrayInputStream(new byte[0]);
}
public java.io.InputStream open(String fileName, int accessMode) throws java.io.IOException {
return open(fileName);
}
public void close() {
// No-op
}
}

View File

@@ -0,0 +1,152 @@
package android.content.res;
/**
* Minimal Resources stub for desktop JVM.
*/
public class Resources {
public Resources() {
}
public Resources(AssetManager assets, android.util.DisplayMetrics metrics, android.content.res.Configuration config) {
}
public CharSequence getText(int id) {
return "";
}
public String getString(int id) {
return "";
}
public String getString(int id, Object... formatArgs) {
return String.format(getString(id), formatArgs);
}
public String getQuantityString(int id, int quantity) {
return getString(id);
}
public String getQuantityString(int id, int quantity, Object... formatArgs) {
return String.format(getQuantityString(id, quantity), formatArgs);
}
public int getColor(int id) {
return 0;
}
public int getColor(int id, Theme theme) {
return getColor(id);
}
public android.graphics.drawable.Drawable getDrawable(int id) {
return null;
}
public android.graphics.drawable.Drawable getDrawable(int id, Theme theme) {
return getDrawable(id);
}
public android.content.res.ColorStateList getColorStateList(int id) {
return null;
}
public android.content.res.ColorStateList getColorStateList(int id, Theme theme) {
return getColorStateList(id);
}
public float getDimension(int id) {
return 0.0f;
}
public int getDimensionPixelSize(int id) {
return 0;
}
public int getDimensionPixelOffset(int id) {
return 0;
}
public android.util.TypedValue getValue(int id, android.util.TypedValue outValue, boolean resolveRefs) {
return outValue;
}
public Theme newTheme() {
return new Theme();
}
public Theme getTheme() {
return new Theme();
}
public AssetManager getAssets() {
return new AssetManager();
}
public android.content.res.XmlResourceParser getXml(int id) {
return null;
}
public android.content.res.XmlResourceParser getAnimation(int id) {
return null;
}
public android.content.res.XmlResourceParser getLayout(int id) {
return null;
}
public String getResourceName(int resid) {
return "";
}
public String getResourcePackageName(int resid) {
return "";
}
public String getResourceTypeName(int resid) {
return "";
}
public String getResourceEntryName(int resid) {
return "";
}
public int getIdentifier(String name, String defType, String defPackage) {
return 0;
}
public java.io.InputStream openRawResource(int id) {
return new java.io.ByteArrayInputStream(new byte[0]);
}
public static class Theme {
public Theme() {
}
public void applyStyle(int resId, boolean force) {
}
public void setTo(Theme other) {
}
public android.content.res.TypedArray obtainStyledAttributes(int[] attrs) {
return null;
}
public android.content.res.TypedArray obtainStyledAttributes(int resid, int[] attrs) throws Resources.NotFoundException {
return null;
}
public android.content.res.TypedArray obtainStyledAttributes(android.util.AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
return null;
}
}
public static class NotFoundException extends RuntimeException {
public NotFoundException() {
}
public NotFoundException(String name) {
super(name);
}
}
}

View File

@@ -0,0 +1,82 @@
package android.hardware;
/**
* Minimal SensorManager stub for desktop JVM.
*/
public class SensorManager {
public static final int SENSOR_DELAY_FASTEST = 0;
public static final int SENSOR_DELAY_GAME = 1;
public static final int SENSOR_DELAY_UI = 2;
public static final int SENSOR_DELAY_NORMAL = 3;
public static final int SENSOR_STATUS_NO_CONTACT = -1;
public static final int SENSOR_STATUS_UNRELIABLE = 0;
public static final int SENSOR_STATUS_ACCURACY_LOW = 1;
public static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2;
public static final int SENSOR_STATUS_ACCURACY_HIGH = 3;
public SensorManager() {
}
public java.util.List<android.hardware.Sensor> getSensorList(int type) {
return new java.util.ArrayList<>();
}
public android.hardware.Sensor getDefaultSensor(int type) {
return null;
}
public android.hardware.Sensor getDefaultSensor(int type, boolean wakeUp) {
return null;
}
public boolean registerListener(android.hardware.SensorEventListener listener, android.hardware.Sensor sensor, int samplingPeriodUs) {
return false;
}
public boolean registerListener(android.hardware.SensorEventListener listener, android.hardware.Sensor sensor, int samplingPeriodUs, android.os.Handler handler) {
return false;
}
public void unregisterListener(android.hardware.SensorEventListener listener) {
// No-op on desktop
}
public void unregisterListener(android.hardware.SensorEventListener listener, android.hardware.Sensor sensor) {
// No-op on desktop
}
public boolean flush(android.hardware.SensorEventListener listener) {
return false;
}
public static float getAltitude(float p0, float p) {
return 44330.0f * (1.0f - (float) Math.pow(p / p0, 1.0f / 5.255f));
}
public static void getRotationMatrixFromVector(float[] R, float[] rotationVector) {
// No-op on desktop
}
public static void getQuaternionFromVector(float[] Q, float[] rv) {
// No-op on desktop
}
public static boolean getRotationMatrix(float[] R, float[] I, float[] gravity, float[] geomagnetic) {
return false;
}
public static float[] getOrientation(float[] R, float[] values) {
if (values == null) {
values = new float[3];
}
values[0] = 0;
values[1] = 0;
values[2] = 0;
return values;
}
public static void remapCoordinateSystem(float[] inR, int X, int Y, float[] outR) {
// No-op on desktop
}
}

View File

@@ -0,0 +1,38 @@
package android.hardware.display;
/**
* Minimal DisplayManager stub for desktop JVM.
*/
public class DisplayManager {
public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
public DisplayManager() {
}
public android.view.Display getDisplay(int displayId) {
return android.view.Display.getDisplay(displayId);
}
public android.view.Display[] getDisplays() {
return new android.view.Display[] { android.view.Display.getDisplay(0) };
}
public android.view.Display[] getDisplays(String category) {
return getDisplays();
}
public void registerDisplayListener(DisplayManager.DisplayListener listener, android.os.Handler handler) {
// No-op on desktop
}
public void unregisterDisplayListener(DisplayManager.DisplayListener listener) {
// No-op on desktop
}
public interface DisplayListener {
void onDisplayAdded(int displayId);
void onDisplayRemoved(int displayId);
void onDisplayChanged(int displayId);
}
}

View File

@@ -0,0 +1,112 @@
package android.location;
/**
* Minimal LocationManager stub for desktop JVM.
*/
public class LocationManager {
public static final String NETWORK_PROVIDER = "network";
public static final String GPS_PROVIDER = "gps";
public static final String PASSIVE_PROVIDER = "passive";
public static final String FUSED_PROVIDER = "fused";
public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
public static final String GPS_ENABLED_CHANGE_ACTION = "android.location.GPS_ENABLED_CHANGE";
public static final String GPS_FIX_CHANGE_ACTION = "android.location.GPS_FIX_CHANGE";
public LocationManager() {
}
public java.util.List<String> getAllProviders() {
return java.util.List.of(NETWORK_PROVIDER, GPS_PROVIDER, PASSIVE_PROVIDER);
}
public java.util.List<String> getProviders(boolean enabledOnly) {
return getAllProviders();
}
public android.location.LocationProvider getProvider(String name) {
return null;
}
public java.util.List<android.location.LocationProvider> getProviders(android.location.Criteria criteria, boolean enabledOnly) {
return new java.util.ArrayList<>();
}
public String getBestProvider(android.location.Criteria criteria, boolean enabledOnly) {
return NETWORK_PROVIDER;
}
public android.location.Location getLastKnownLocation(String provider) {
return null;
}
public void requestLocationUpdates(String provider, long minTime, float minDistance, android.location.LocationListener listener) {
// No-op on desktop
}
public void requestLocationUpdates(String provider, long minTime, float minDistance, android.location.LocationListener listener, android.os.Looper looper) {
// No-op on desktop
}
public void requestSingleUpdate(String provider, android.location.LocationListener listener, android.os.Looper looper) {
// No-op on desktop
}
public void removeUpdates(android.location.LocationListener listener) {
// No-op on desktop
}
public boolean isProviderEnabled(String provider) {
return false;
}
public boolean isLocationEnabled() {
return false;
}
public void addGpsStatusListener(android.location.GpsStatus.Listener listener) {
// No-op on desktop
}
public void removeGpsStatusListener(android.location.GpsStatus.Listener listener) {
// No-op on desktop
}
public boolean addNmeaListener(android.location.OnNmeaMessageListener listener) {
return false;
}
public boolean addNmeaListener(android.location.OnNmeaMessageListener listener, android.os.Handler handler) {
return false;
}
public void removeNmeaListener(android.location.OnNmeaMessageListener listener) {
// No-op on desktop
}
public boolean registerGnssStatusCallback(android.location.GnssStatus.Callback callback) {
return false;
}
public boolean registerGnssStatusCallback(android.location.GnssStatus.Callback callback, android.os.Handler handler) {
return false;
}
public void unregisterGnssStatusCallback(android.location.GnssStatus.Callback callback) {
// No-op on desktop
}
public void addProximityAlert(double latitude, double longitude, float radius, long expiration, android.app.PendingIntent intent) {
// No-op on desktop
}
public void removeProximityAlert(android.app.PendingIntent intent) {
// No-op on desktop
}
public boolean sendExtraCommand(String provider, String command, android.os.Bundle extras) {
return false;
}
}

View File

@@ -0,0 +1,114 @@
package android.media;
/**
* Minimal AudioManager stub for desktop JVM.
*/
public class AudioManager {
public static final int STREAM_VOICE_CALL = 0;
public static final int STREAM_SYSTEM = 1;
public static final int STREAM_RING = 2;
public static final int STREAM_MUSIC = 3;
public static final int STREAM_ALARM = 4;
public static final int STREAM_NOTIFICATION = 5;
public static final int STREAM_DTMF = 8;
public static final int STREAM_ACCESSIBILITY = 10;
public static final int MODE_NORMAL = 0;
public static final int MODE_RINGTONE = 1;
public static final int MODE_IN_CALL = 2;
public static final int MODE_IN_COMMUNICATION = 3;
public static final int RINGER_MODE_SILENT = 0;
public static final int RINGER_MODE_VIBRATE = 1;
public static final int RINGER_MODE_NORMAL = 2;
public static final int AUDIOFOCUS_GAIN = 1;
public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
public static final int AUDIOFOCUS_LOSS = -1;
public static final int AUDIOFOCUS_LOSS_TRANSIENT = -2;
public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = -3;
public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
public AudioManager() {
}
public int getStreamMaxVolume(int streamType) {
return 15;
}
public int getStreamVolume(int streamType) {
return 10;
}
public void setStreamVolume(int streamType, int index, int flags) {
// No-op on desktop
}
public int getRingerMode() {
return RINGER_MODE_NORMAL;
}
public void setRingerMode(int ringerMode) {
// No-op on desktop
}
public boolean isMusicActive() {
return false;
}
public void requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener l, int streamType, int durationHint) {
// No-op on desktop
}
public int requestAudioFocus(android.media.AudioFocusRequest focusRequest) {
return AUDIOFOCUS_REQUEST_GRANTED;
}
public void abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener l) {
// No-op on desktop
}
public int abandonAudioFocusRequest(android.media.AudioFocusRequest focusRequest) {
return AUDIOFOCUS_REQUEST_GRANTED;
}
public boolean isSpeakerphoneOn() {
return false;
}
public void setSpeakerphoneOn(boolean on) {
// No-op on desktop
}
public boolean isBluetoothScoOn() {
return false;
}
public void setBluetoothScoOn(boolean on) {
// No-op on desktop
}
public void startBluetoothSco() {
// No-op on desktop
}
public void stopBluetoothSco() {
// No-op on desktop
}
public void setMode(int mode) {
// No-op on desktop
}
public int getMode() {
return MODE_NORMAL;
}
public interface OnAudioFocusChangeListener {
void onAudioFocusChange(int focusChange);
}
}

View File

@@ -0,0 +1,56 @@
package android.net;
/**
* Minimal ConnectivityManager stub for desktop JVM.
*/
public class ConnectivityManager {
public static final int TYPE_MOBILE = 0;
public static final int TYPE_WIFI = 1;
public static final int TYPE_BLUETOOTH = 7;
public static final int TYPE_ETHERNET = 9;
public static final int TYPE_VPN = 17;
public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1;
public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2;
public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3;
public ConnectivityManager() {
}
public android.net.NetworkInfo getActiveNetworkInfo() {
// Always report as connected on desktop
return new android.net.NetworkInfo(TYPE_WIFI, 0, "WIFI", "");
}
public android.net.Network getActiveNetwork() {
return null;
}
public boolean isActiveNetworkMetered() {
return false;
}
public int getRestrictBackgroundStatus() {
return RESTRICT_BACKGROUND_STATUS_DISABLED;
}
public boolean getNetworkInfo(int networkType) {
return networkType == TYPE_WIFI || networkType == TYPE_ETHERNET;
}
public void registerNetworkCallback(android.net.NetworkRequest request, android.net.ConnectivityManager.NetworkCallback networkCallback) {
// No-op on desktop
}
public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback networkCallback) {
// No-op on desktop
}
public static abstract class NetworkCallback {
public void onAvailable(android.net.Network network) {}
public void onLost(android.net.Network network) {}
public void onCapabilitiesChanged(android.net.Network network, android.net.NetworkCapabilities networkCapabilities) {}
public void onLinkPropertiesChanged(android.net.Network network, android.net.LinkProperties linkProperties) {}
}
}

View File

@@ -0,0 +1,60 @@
package android.net.wifi;
/**
* Minimal WifiManager stub for desktop JVM.
*/
public class WifiManager {
public static final int WIFI_STATE_DISABLING = 0;
public static final int WIFI_STATE_DISABLED = 1;
public static final int WIFI_STATE_ENABLING = 2;
public static final int WIFI_STATE_ENABLED = 3;
public static final int WIFI_STATE_UNKNOWN = 4;
public WifiManager() {
}
public int getWifiState() {
return WIFI_STATE_ENABLED;
}
public boolean isWifiEnabled() {
return true;
}
public boolean setWifiEnabled(boolean enabled) {
return false;
}
public android.net.wifi.WifiInfo getConnectionInfo() {
return new android.net.wifi.WifiInfo();
}
public java.util.List<android.net.wifi.ScanResult> getScanResults() {
return new java.util.ArrayList<>();
}
public boolean startScan() {
return false;
}
public int addNetwork(android.net.wifi.WifiConfiguration config) {
return -1;
}
public boolean disconnect() {
return false;
}
public boolean reconnect() {
return false;
}
public boolean is5GHzBandSupported() {
return true;
}
public boolean isP2pSupported() {
return false;
}
}

View File

@@ -0,0 +1,43 @@
package android.net.wifi.p2p;
/**
* Minimal WifiP2pManager stub for desktop JVM.
*/
public class WifiP2pManager {
public static final int ERROR = 0;
public static final int P2P_UNSUPPORTED = 1;
public static final int BUSY = 2;
public static final int NO_SERVICE_REQUESTS = 3;
public WifiP2pManager() {
}
public void initialize(android.content.Context srcContext, android.os.Looper srcLooper, WifiP2pManager.ChannelListener listener) {
// No-op on desktop
}
public void discoverPeers(android.net.wifi.p2p.WifiP2pManager.Channel c, android.net.wifi.p2p.WifiP2pManager.ActionListener listener) {
if (listener != null) {
listener.onFailure(P2P_UNSUPPORTED);
}
}
public void stopPeerDiscovery(android.net.wifi.p2p.WifiP2pManager.Channel c, android.net.wifi.p2p.WifiP2pManager.ActionListener listener) {
if (listener != null) {
listener.onFailure(P2P_UNSUPPORTED);
}
}
public interface ChannelListener {
void onChannelDisconnected();
}
public interface ActionListener {
void onSuccess();
void onFailure(int reason);
}
public static class Channel {
}
}

View File

@@ -0,0 +1,14 @@
package android.nfc;
/**
* Minimal NfcManager stub for desktop JVM.
*/
public class NfcManager {
public NfcManager() {
}
public android.nfc.NfcAdapter getDefaultAdapter() {
return null;
}
}

View File

@@ -0,0 +1,76 @@
package android.os;
/**
* Minimal BatteryManager stub for desktop JVM.
*/
public class BatteryManager {
public static final String EXTRA_HEALTH = "health";
public static final String EXTRA_STATUS = "status";
public static final String EXTRA_LEVEL = "level";
public static final String EXTRA_SCALE = "scale";
public static final String EXTRA_PLUGGED = "plugged";
public static final String EXTRA_VOLTAGE = "voltage";
public static final String EXTRA_TEMPERATURE = "temperature";
public static final String EXTRA_PRESENT = "present";
public static final String EXTRA_TECHNOLOGY = "technology";
public static final String EXTRA_CYCLE_COUNT = "cycle_count";
public static final int BATTERY_STATUS_UNKNOWN = 1;
public static final int BATTERY_STATUS_CHARGING = 2;
public static final int BATTERY_STATUS_DISCHARGING = 3;
public static final int BATTERY_STATUS_NOT_CHARGING = 4;
public static final int BATTERY_STATUS_FULL = 5;
public static final int BATTERY_HEALTH_UNKNOWN = 1;
public static final int BATTERY_HEALTH_GOOD = 2;
public static final int BATTERY_HEALTH_OVERHEAT = 3;
public static final int BATTERY_HEALTH_DEAD = 4;
public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5;
public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;
public static final int BATTERY_HEALTH_COLD = 7;
public static final int BATTERY_PLUGGED_AC = 1;
public static final int BATTERY_PLUGGED_USB = 2;
public static final int BATTERY_PLUGGED_WIRELESS = 4;
public static final int BATTERY_PLUGGED_DOCK = 8;
public BatteryManager() {
}
public int getIntProperty(int id) {
return switch (id) {
case BATTERY_PROPERTY_STATUS -> BATTERY_STATUS_FULL;
case BATTERY_PROPERTY_HEALTH -> BATTERY_HEALTH_GOOD;
case BATTERY_PROPERTY_PRESENT -> 1;
case BATTERY_PROPERTY_LEVEL -> 100;
case BATTERY_PROPERTY_SCALE -> 100;
case BATTERY_PROPERTY_VOLTAGE -> 4200;
case BATTERY_PROPERTY_TEMPERATURE -> 250;
case BATTERY_PROPERTY_CAPACITY -> 100;
case BATTERY_PROPERTY_CHARGE_COUNTER -> 4000000;
default -> 0;
};
}
public long getLongProperty(int id) {
return getIntProperty(id);
}
public boolean isCharging() {
return false;
}
public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1;
public static final int BATTERY_PROPERTY_CURRENT_NOW = 2;
public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3;
public static final int BATTERY_PROPERTY_CAPACITY = 4;
public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5;
public static final int BATTERY_PROPERTY_STATUS = 6;
public static final int BATTERY_PROPERTY_HEALTH = 7;
public static final int BATTERY_PROPERTY_PRESENT = 8;
public static final int BATTERY_PROPERTY_LEVEL = 9;
public static final int BATTERY_PROPERTY_SCALE = 10;
public static final int BATTERY_PROPERTY_VOLTAGE = 11;
public static final int BATTERY_PROPERTY_TEMPERATURE = 12;
}

View File

@@ -0,0 +1,78 @@
package android.os;
/**
* Minimal PowerManager stub for desktop JVM.
*/
public class PowerManager {
public static final int PARTIAL_WAKE_LOCK = 0x00000001;
public static final int FULL_WAKE_LOCK = 0x0000001a;
public static final int SCREEN_BRIGHT_WAKE_LOCK = 0x0000000a;
public static final int SCREEN_DIM_WAKE_LOCK = 0x00000006;
public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
public static final int ON_AFTER_RELEASE = 0x20000000;
public static final int BRIGHTNESS_ON = 255;
public static final int BRIGHTNESS_OFF = 0;
public PowerManager() {
}
public PowerManager.WakeLock newWakeLock(int levelAndFlags, String tag) {
return new PowerManager.WakeLock();
}
public boolean isWakeLockLevelSupported(int level) {
return false;
}
public boolean isDeviceIdleMode() {
return false;
}
public boolean isPowerSaveMode() {
return false;
}
public boolean isInteractive() {
return true;
}
public boolean isScreenOn() {
return true;
}
public void reboot(String reason) {
// No-op on desktop
}
public static class WakeLock {
public void acquire() {
// No-op on desktop
}
public void acquire(long timeout) {
// No-op on desktop
}
public void release() {
// No-op on desktop
}
public void release(int flags) {
// No-op on desktop
}
public boolean isHeld() {
return false;
}
public void setReferenceCounted(boolean value) {
// No-op on desktop
}
public void setWorkSource(android.os.WorkSource ws) {
// No-op on desktop
}
}
}

View File

@@ -0,0 +1,34 @@
package android.os;
/**
* Minimal Vibrator stub for desktop JVM.
*/
public class Vibrator {
public Vibrator() {
}
public boolean hasVibrator() {
return false;
}
public boolean hasAmplitudeControl() {
return false;
}
public void vibrate(long milliseconds) {
// No-op on desktop
}
public void vibrate(long[] pattern, int repeat) {
// No-op on desktop
}
public void vibrate(android.os.VibrationEffect vibe) {
// No-op on desktop
}
public void cancel() {
// No-op on desktop
}
}

View File

@@ -0,0 +1,34 @@
package android.os.storage;
/**
* Minimal StorageManager stub for desktop JVM.
*/
public class StorageManager {
public StorageManager() {
}
public java.util.List<android.os.storage.StorageVolume> getStorageVolumes() {
return new java.util.ArrayList<>();
}
public android.os.storage.StorageVolume getPrimaryStorageVolume() {
return null;
}
public long getPrimaryStorageSize() {
return new java.io.File("/").getTotalSpace();
}
public java.util.UUID getUuidForPath(java.io.File path) {
return java.util.UUID.randomUUID();
}
public boolean isEncrypted(java.io.File file) {
return false;
}
public boolean isAllocationSupported(java.io.FileDescriptor fd) {
return false;
}
}

View File

@@ -0,0 +1,159 @@
package android.telephony;
/**
* Minimal TelephonyManager stub for desktop JVM.
*/
public class TelephonyManager {
public static final int NETWORK_TYPE_UNKNOWN = 0;
public static final int NETWORK_TYPE_GPRS = 1;
public static final int NETWORK_TYPE_EDGE = 2;
public static final int NETWORK_TYPE_UMTS = 3;
public static final int NETWORK_TYPE_CDMA = 4;
public static final int NETWORK_TYPE_EVDO_0 = 5;
public static final int NETWORK_TYPE_EVDO_A = 6;
public static final int NETWORK_TYPE_1xRTT = 7;
public static final int NETWORK_TYPE_HSDPA = 8;
public static final int NETWORK_TYPE_HSUPA = 9;
public static final int NETWORK_TYPE_HSPA = 10;
public static final int NETWORK_TYPE_IDEN = 11;
public static final int NETWORK_TYPE_EVDO_B = 12;
public static final int NETWORK_TYPE_LTE = 13;
public static final int NETWORK_TYPE_EHRPD = 14;
public static final int NETWORK_TYPE_HSPAP = 15;
public static final int NETWORK_TYPE_GSM = 16;
public static final int NETWORK_TYPE_TD_SCDMA = 17;
public static final int NETWORK_TYPE_IWLAN = 18;
public static final int NETWORK_TYPE_NR = 20;
public static final int CALL_STATE_IDLE = 0;
public static final int CALL_STATE_RINGING = 1;
public static final int CALL_STATE_OFFHOOK = 2;
public static final int DATA_DISCONNECTED = 0;
public static final int DATA_CONNECTING = 1;
public static final int DATA_CONNECTED = 2;
public static final int DATA_SUSPENDED = 3;
public static final int SIM_STATE_UNKNOWN = 0;
public static final int SIM_STATE_ABSENT = 1;
public static final int SIM_STATE_PIN_REQUIRED = 2;
public static final int SIM_STATE_PUK_REQUIRED = 3;
public static final int SIM_STATE_NETWORK_LOCKED = 4;
public static final int SIM_STATE_READY = 5;
public TelephonyManager() {
}
public String getDeviceId() {
return "000000000000000";
}
public String getDeviceId(int slotIndex) {
return "000000000000000";
}
public String getImei() {
return "000000000000000";
}
public String getImei(int slotIndex) {
return "000000000000000";
}
public String getMeid() {
return "00000000000000";
}
public String getMeid(int slotIndex) {
return "00000000000000";
}
public String getSubscriberId() {
return "000000000000000";
}
public String getGroupIdLevel1() {
return "";
}
public String getLine1Number() {
return "";
}
public String getNetworkCountryIso() {
return "US";
}
public String getSimCountryIso() {
return "US";
}
public String getNetworkOperator() {
return "00000";
}
public String getNetworkOperatorName() {
return "Desktop";
}
public String getSimOperator() {
return "00000";
}
public String getSimOperatorName() {
return "Desktop";
}
public int getCallState() {
return CALL_STATE_IDLE;
}
public int getDataState() {
return DATA_DISCONNECTED;
}
public int getDataActivity() {
return 0;
}
public int getNetworkType() {
return NETWORK_TYPE_UNKNOWN;
}
public int getPhoneType() {
return 0;
}
public int getSimState() {
return SIM_STATE_ABSENT;
}
public int getSimState(int slotIndex) {
return SIM_STATE_ABSENT;
}
public boolean isNetworkRoaming() {
return false;
}
public boolean hasIccCard() {
return false;
}
public int getDataNetworkType() {
return NETWORK_TYPE_UNKNOWN;
}
public int getVoiceNetworkType() {
return NETWORK_TYPE_UNKNOWN;
}
public boolean isSmsCapable() {
return false;
}
public boolean isVoiceCapable() {
return false;
}
}

View File

@@ -0,0 +1,87 @@
package android.view;
/**
* Minimal Display stub for desktop JVM.
*/
public class Display {
public static final int DEFAULT_DISPLAY = 0;
public static final int INVALID_DISPLAY = -1;
public static final int STATE_UNKNOWN = 0;
public static final int STATE_OFF = 1;
public static final int STATE_ON = 2;
public static final int STATE_DOZE = 3;
public static final int STATE_DOZE_SUSPEND = 4;
public static final int STATE_VR = 5;
public static final int STATE_ON_SUSPEND = 6;
public Display() {
}
public static Display getDisplay(int displayId) {
return new Display();
}
public int getDisplayId() {
return DEFAULT_DISPLAY;
}
public String getName() {
return "Desktop Display";
}
public int getWidth() {
return 1920;
}
public int getHeight() {
return 1080;
}
public int getRotation() {
return 0;
}
public int getOrientation() {
return 0;
}
public float getRefreshRate() {
return 60.0f;
}
public int getState() {
return STATE_ON;
}
public void getMetrics(android.util.DisplayMetrics outMetrics) {
if (outMetrics != null) {
outMetrics.widthPixels = getWidth();
outMetrics.heightPixels = getHeight();
outMetrics.density = 1.0f;
outMetrics.densityDpi = 160;
outMetrics.scaledDensity = 1.0f;
outMetrics.xdpi = 160.0f;
outMetrics.ydpi = 160.0f;
}
}
public void getRealMetrics(android.util.DisplayMetrics outMetrics) {
getMetrics(outMetrics);
}
public void getSize(android.graphics.Point outSize) {
if (outSize != null) {
outSize.x = getWidth();
outSize.y = getHeight();
}
}
public void getRealSize(android.graphics.Point outSize) {
getSize(outSize);
}
public int getFlags() {
return 0;
}
}

View File

@@ -0,0 +1,30 @@
package android.view;
/**
* Minimal LayoutInflater stub for desktop JVM.
*/
public class LayoutInflater {
public LayoutInflater() {
}
public static android.view.LayoutInflater from(android.content.Context context) {
return new android.view.LayoutInflater();
}
public android.view.View inflate(int resource, android.view.ViewGroup root) {
return null;
}
public android.view.View inflate(int resource, android.view.ViewGroup root, boolean attachToRoot) {
return null;
}
public android.view.View inflate(org.xmlpull.v1.XmlPullParser parser, android.view.ViewGroup root) {
return null;
}
public android.view.View inflate(org.xmlpull.v1.XmlPullParser parser, android.view.ViewGroup root, boolean attachToRoot) {
return null;
}
}

View File

@@ -0,0 +1,40 @@
package android.view;
/**
* Minimal WindowManager stub for desktop JVM.
*/
public class WindowManager {
public WindowManager() {
}
public android.view.Display getDefaultDisplay() {
return new android.view.Display();
}
public void removeView(android.view.View view) {
// No-op on desktop
}
public void removeViewImmediate(android.view.View view) {
// No-op on desktop
}
public void addView(android.view.View view, android.view.ViewGroup.LayoutParams params) {
// No-op on desktop
}
public void updateViewLayout(android.view.View view, android.view.ViewGroup.LayoutParams params) {
// No-op on desktop
}
public interface LayoutParams {
int MATCH_PARENT = -1;
int WRAP_CONTENT = -2;
int TYPE_APPLICATION = 2;
int TYPE_SYSTEM_ALERT = 2010;
int FLAG_NOT_FOCUSABLE = 0x00000008;
int FLAG_NOT_TOUCHABLE = 0x00000010;
int FLAG_KEEP_SCREEN_ON = 0x00000080;
}
}

View File

@@ -0,0 +1,58 @@
package android.view.accessibility;
/**
* Minimal AccessibilityManager stub for desktop JVM.
*/
public class AccessibilityManager {
public AccessibilityManager() {
}
public boolean isEnabled() {
return false;
}
public boolean isTouchExplorationEnabled() {
return false;
}
public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent event) {
// No-op on desktop
}
public void interrupt() {
// No-op on desktop
}
public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList() {
return new java.util.ArrayList<>();
}
public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackTypeFlags) {
return new java.util.ArrayList<>();
}
public void addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener listener) {
// No-op on desktop
}
public void removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener listener) {
// No-op on desktop
}
public void addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener listener) {
// No-op on desktop
}
public void removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener listener) {
// No-op on desktop
}
public interface AccessibilityStateChangeListener {
void onAccessibilityStateChanged(boolean enabled);
}
public interface TouchExplorationStateChangeListener {
void onTouchExplorationStateChanged(boolean enabled);
}
}

View File

@@ -0,0 +1,43 @@
package android.view.inputmethod;
/**
* Minimal InputMethodManager stub for desktop JVM.
*/
public class InputMethodManager {
public static final int SHOW_IMPLICIT = 0x0001;
public static final int SHOW_FORCED = 0x0002;
public static final int HIDE_IMPLICIT_ONLY = 0x0001;
public static final int HIDE_NOT_ALWAYS = 0x0002;
public InputMethodManager() {
}
public boolean showSoftInput(android.view.View view, int flags) {
return false;
}
public boolean showSoftInput(android.view.View view, int flags, android.os.ResultReceiver resultReceiver) {
return false;
}
public boolean hideSoftInputFromWindow(android.os.IBinder windowToken, int flags) {
return false;
}
public boolean hideSoftInputFromWindow(android.os.IBinder windowToken, int flags, android.os.ResultReceiver resultReceiver) {
return false;
}
public void toggleSoftInput(int showFlags, int hideFlags) {
// No-op on desktop
}
public void restartInput(android.view.View view) {
// No-op on desktop
}
public void updateSelection(android.view.View view, int selStart, int selEnd, int candidatesStart, int candidatesEnd) {
// No-op on desktop
}
}

View File

@@ -5,9 +5,6 @@ import android.content.Context
class EditTextPreference(val context: Context?) : Preference() {
var dialogTitle: String? = null
var dialogMessage: String? = null
var entries: Array<String>? = null
var entryValues: Array<String> = emptyArray()
var summary: String? = null
var defaultValue: String? = null
var setDefaultValue: ((String) -> Unit) = {defaultValue = it}

View File

@@ -3,9 +3,6 @@ package androidx.preference
import android.content.Context
class ListPreference(val context: Context?) : Preference(){
var entries: Array<String>? = null
var entryValues: Array<String> = emptyArray()
var summary: String? = null
var defaultValue: String? = null
var setDefaultValue: ((String) -> Unit) = {defaultValue = it}

View File

@@ -3,9 +3,6 @@ package androidx.preference
import android.content.Context
class MultiSelectListPreference(val context: Context?) : Preference() {
var entries: Array<String>? = null
var entryValues: Array<String> = emptyArray()
var summary: String? = null
var defaultValue: Set<String>? = null
var setDefaultValue: ((Set<String>) -> Unit) = {defaultValue = it}

View File

@@ -3,6 +3,9 @@ package androidx.preference
open class Preference {
var key: String? = null
var title: String? = null
var entries: Array<String>? = null
var entryValues: Array<String> = emptyArray()
var summary: String? = null
fun setKey(key: CharSequence?) {
this.key = key.toString()

View File

@@ -13,56 +13,64 @@ public class PreferenceScreen {
List<Preference> listPreferences = new ArrayList<>();
public PreferenceScreen(Context context, SharedPreferences sharedPrefs) {
this.context = context;
this.sharedPrefs = sharedPrefs;
}
public boolean addPreference(Preference preference) {
listPreferences.add(preference);
SharedPreferences.Editor editor = sharedPrefs.edit();
if (preference instanceof SwitchPreferenceCompat switchPreference) {
if (switchPreference.getDefaultValue() == null) {
return false;
}
sharedPrefs.putBoolean(switchPreference.getKey(), switchPreference.getDefaultValue());
editor.putBoolean(switchPreference.getKey(), switchPreference.getDefaultValue());
} else if (preference instanceof EditTextPreference editTextPreference) {
if (editTextPreference.getDefaultValue() == null) {
return false;
}
sharedPrefs.putString(editTextPreference.getKey(), editTextPreference.getDefaultValue());
editor.putString(editTextPreference.getKey(), editTextPreference.getDefaultValue());
} else if (preference instanceof ListPreference listPreference) {
if (listPreference.getDefaultValue() == null) {
return false;
}
sharedPrefs.putString(listPreference.getKey(), listPreference.getDefaultValue());
editor.putString(listPreference.getKey(), listPreference.getDefaultValue());
} else if (preference instanceof MultiSelectListPreference multiSelectListPreference) {
if (multiSelectListPreference.getDefaultValue() == null) {
return false;
}
sharedPrefs.putStringSet(multiSelectListPreference.getKey(), multiSelectListPreference.getDefaultValue());
editor.putStringSet(multiSelectListPreference.getKey(), multiSelectListPreference.getDefaultValue());
}
editor.apply();
return true;
}
public boolean editPreference(String key, Object value) {
for (Preference preference : listPreferences) {
if (preference.getKey() != null && preference.getKey().equals(key)) {
SharedPreferences.Editor editor = sharedPrefs.edit();
if (preference instanceof SwitchPreferenceCompat) {
if (value instanceof Boolean booleanValue) {
sharedPrefs.putBoolean(key, booleanValue);
editor.putBoolean(key, booleanValue);
editor.apply();
return true;
}
} else if (preference instanceof EditTextPreference) {
if (value instanceof String stringValue) {
sharedPrefs.putString(key, stringValue);
editor.putString(key, stringValue);
editor.apply();
return true;
}
} else if (preference instanceof ListPreference) {
if (value instanceof String stringValue) {
sharedPrefs.putString(key, stringValue);
editor.putString(key, stringValue);
editor.apply();
return true;
}
} else if (preference instanceof MultiSelectListPreference) {
if (value instanceof String listValue) {
sharedPrefs.putStringSet(key, Set.of(listValue.split(";")));
editor.putStringSet(key, Set.of(listValue.split(";")));
editor.apply();
return true;
}
}

View File

@@ -3,9 +3,6 @@ package androidx.preference
import android.content.Context
class SwitchPreferenceCompat(val context: Context?) : Preference() {
var entries: Array<String>? = null
var entryValues: Array<String> = emptyArray()
var summary: String? = null
var defaultValue: Boolean? = null
var visible: Boolean = true
var setDefaultValue: ((Boolean) -> Unit) = { defaultValue = it }

View File

@@ -261,6 +261,24 @@
<include>**</include>
</includes>
</filter>
<!--
Force-include all Kotlin runtime classes.
Extensions are loaded dynamically and reference internal Kotlin
classes (e.g. SpillingKt) that our core code never directly
imports. Without this, maven-shade-plugin strips them.
-->
<filter>
<artifact>org.jetbrains.kotlin:*</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>org.jetbrains.kotlinx:*</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters>
</configuration>
</execution>

View File

@@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.network
import android.app.Application
import android.content.Context
import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor
import eu.kanade.tachiyomi.network.interceptor.IgnoreGzipInterceptor
@@ -26,7 +27,7 @@ class NetworkHelper(
.callTimeout(2, TimeUnit.MINUTES)
.cache(
Cache(
directory = File(Context.getCacheDir(), "network_cache"),
directory = File(Application.getInstance().getApplicationContext().getCacheDir(), "network_cache"),
maxSize = 5L * 1024 * 1024, // 5 MiB
),
)
@@ -67,7 +68,7 @@ class NetworkHelper(
val client = clientBuilder
.addInterceptor(
CloudflareInterceptor(Context(), cookieJar, ::defaultUserAgentProvider),
CloudflareInterceptor(Application.getInstance().getApplicationContext(), cookieJar, ::defaultUserAgentProvider),
)
.build()

View File

@@ -4,4 +4,4 @@
mvn clean package
# Replace the old jar with the new compiled JAR to the app directory and rename it to the expected name
cp target/aniyomibridge-core-1.0.0.jar /home/kevin/Projects/k3vinb5_aniyomi_bridge/assets/aniyomibridge-core.jar
cp aniyomibridge-core/target/aniyomibridge-core-1.0.0.jar /home/kevin/Projects/k3vinb5_aniyomi_bridge/assets/aniyomibridge-core.jar