Commit a8199e8b authored by Lisa (AI Assistant)'s avatar Lisa (AI Assistant)

Refactor to com.nexlab.openclaw.node package - Add NodeService with WebSocket connection

parent 6e978557

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

#Mon Mar 09 11:06:55 SAST 2026
gradle.version=8.4
# OpenClaw Android Node # OpenClaw Android Node
An Android app that turns any Android device into an OpenClaw node, enabling remote control and automation. An Android app that turns your device into a remote node for OpenClaw - allowing remote control, automation, and device management.
## Features ## Package Name
-**WebSocket Node Protocol** - Connect to OpenClaw gateway
-**Screenshot Capture** - Real-time screen capture via MediaProjection
-**Touch Control** - Tap, swipe, long press via AccessibilityService
-**App Control** - Launch apps by package name
-**Shell Execution** - Execute safe shell commands
-**Device Info** - Battery, storage, network status
-**Notification Mirroring** - Forward notifications to gateway
-**Settings UI** - Configure gateway URL, token, node ID
## Upcoming Features
- 🔐 **Permission System** - Allowlist + confirmation for sensitive actions (camera, mic)
- 📷 **Camera Access** - Capture photos/video
- 🎤 **Microphone Access** - Record audio
- 🔊 **Audio Playback** - Play audio files
- 💬 **Chat Interface** - Text + voice messages with AI
-**Donations** - PayPal, BTC, ETH, credit card (details TBD)
## Requirements
- Android 8.0+ (API 26+)
- Internet connection
## Permissions Required **com.nexlab.openclaw.node**
- **Accessibility** - For touch gestures (tap, swipe) ## Features
- **Notification Access** - For notification mirroring
- Internet
- Foreground Service
## Quick Start
1. Clone and build: `./gradlew assembleDebug` - 🌐 WebSocket-based remote control protocol
2. Install the APK on your Android device - 📸 Screenshot capture
3. Grant Accessibility permission when prompted - 👆 Touch control (tap, swipe, long press)
4. Enter your OpenClaw gateway URL and token - 🎥 Camera access (photo + video)
5. Tap Connect - 🎤 Microphone recording
- 🔊 Audio playback
- 🔔 Notification mirroring
- 📱 App launching
- 🔐 Permission management system
## Architecture
- **Language:** Kotlin
- **DI:** Hilt
- **UI:** Jetpack Compose
- **Networking:** OkHttp WebSocket
- **Target SDK:** 34 (Android 14)
- **Min SDK:** 26 (Android 8.0)
## Building ## Building
```bash ```bash
# Debug APK export ANDROID_HOME=~/android-sdk
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
./gradlew assembleDebug ./gradlew assembleDebug
# Release APK (requires signing config)
./gradlew assembleRelease
``` ```
## Documentation APK output: `app/build/outputs/apk/debug/app-debug.apk`
See [SPEC.md](SPEC.md) for detailed architecture. ## Future Considerations
## Project Structure ### Competitor Analysis
``` - **Granola.ai** - Similar concept to OpenClaw but sold as a SaaS service ($X/user/month). OpenClaw could potentially be offered as a self-hosted or managed service in the future.
app/src/main/java/com/openclaw/node/
├── OpenClawApp.kt # Application class
├── di/ # Hilt dependency injection
├── data/
│ ├── remote/ # WebSocket client
│ └── repository/ # Settings storage
├── domain/model/ # Domain models
├── service/
│ ├── NodeService.kt # Main foreground service
│ ├── ScreenshotService.kt
│ ├── TouchService.kt # AccessibilityService
│ └── NotificationListener.kt
└── ui/ # Jetpack Compose UI
```
## License ## License
MIT Proprietary - All rights reserved
plugins { plugins {
id 'com.android.application' id("com.android.application")
id 'org.jetbrains.kotlin.android' id("org.jetbrains.kotlin.android")
id 'com.google.dagger.hilt.android' id("com.google.dagger.hilt.android")
id 'kotlin-kapt' id("kotlin-kapt")
} }
android { android {
namespace 'com.openclaw.node' namespace = "com.nexlab.openclaw.node"
compileSdk 34 compileSdk = 34
defaultConfig { defaultConfig {
applicationId "com.openclaw.node" applicationId = "com.nexlab.openclaw.node"
minSdk 26 minSdk = 26
targetSdk 34 targetSdk = 34
versionCode 1 versionCode = 1
versionName "0.1.0" versionName = "0.1.0"
multiDexEnabled = true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables { vectorDrawables {
useSupportLibrary true useSupportLibrary = true
} }
} }
buildTypes { buildTypes {
release { release {
minifyEnabled false isMinifyEnabled = false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
} }
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_17 sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17
} }
kotlinOptions { kotlinOptions {
jvmTarget = '17' jvmTarget = "17"
} }
buildFeatures { buildFeatures {
compose true compose = true
} }
composeOptions { composeOptions {
kotlinCompilerExtensionVersion '1.5.5' kotlinCompilerExtensionVersion = "1.5.5"
} }
packaging { packaging {
resources { resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}' excludes += "/META-INF/{AL2.0,LGPL2.1}"
} }
} }
} }
dependencies { dependencies {
// Multidex
implementation("androidx.multidex:multidex:2.0.1")
// Core Android // Core Android
implementation 'androidx.core:core-ktx:1.12.0' implementation("androidx.core:core-ktx:1.12.0")
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2' implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
implementation 'androidx.activity:activity-compose:1.8.1' implementation("androidx.activity:activity-compose:1.8.1")
// Compose // Compose
implementation platform('androidx.compose:compose-bom:2023.10.01') implementation(platform("androidx.compose:compose-bom:2023.10.01"))
implementation 'androidx.compose.ui:ui' implementation("androidx.compose.ui:ui")
implementation 'androidx.compose.ui:ui-graphics' implementation("androidx.compose.ui:ui-graphics")
implementation 'androidx.compose.ui:ui-tooling-preview' implementation("androidx.compose.ui:ui-tooling-preview")
implementation 'androidx.compose.material3:material3' implementation("androidx.compose.material3:material3")
// Hilt // Hilt
implementation 'com.google.dagger:hilt-android:2.48.1' implementation("com.google.dagger:hilt-android:2.48.1")
kapt 'com.google.dagger:hilt-android-compiler:2.48.1' kapt("com.google.dagger:hilt-android-compiler:2.48.1")
implementation 'androidx.hilt:hilt-navigation-compose:1.1.0' implementation("androidx.hilt:hilt-navigation-compose:1.1.0")
// Networking // Networking
implementation 'com.squareup.okhttp3:okhttp:4.12.0' implementation("com.squareup.okhttp3:okhttp:4.12.0")
// Coroutines // Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3' implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
// DataStore // DataStore
implementation 'androidx.datastore:datastore-preferences:1.0.0' implementation("androidx.datastore:datastore-preferences:1.0.0")
// Navigation // Navigation
implementation 'androidx.navigation:navigation-compose:2.7.5' implementation("androidx.navigation:navigation-compose:2.7.5")
// QR Code (for pairing) // QR Code (for pairing)
implementation 'com.google.zxing:core:3.5.2' implementation("com.google.zxing:core:3.5.2")
// Testing // Testing
testImplementation 'junit:junit:4.13.2' testImplementation("junit:junit:4.13.2")
androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation platform('androidx.compose:compose-bom:2023.10.01') androidTestImplementation(platform("androidx.compose:compose-bom:2023.10.01"))
androidTestImplementation 'androidx.compose.ui:ui-test-junit4' androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation 'androidx.compose.ui:ui-tooling' debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation 'androidx.compose.ui:ui-test-manifest' debugImplementation("androidx.compose.ui:ui-test-manifest")
} }
kapt { kapt {
correctErrorTypes true correctErrorTypes = true
} }
package com.nexlab.openclaw.node;
import android.app.Application;
import androidx.annotation.CallSuper;
import dagger.hilt.android.internal.managers.ApplicationComponentManager;
import dagger.hilt.android.internal.managers.ComponentSupplier;
import dagger.hilt.android.internal.modules.ApplicationContextModule;
import dagger.hilt.internal.GeneratedComponentManagerHolder;
import dagger.hilt.internal.UnsafeCasts;
import java.lang.Object;
import java.lang.Override;
import javax.annotation.processing.Generated;
/**
* A generated base class to be extended by the @dagger.hilt.android.HiltAndroidApp annotated class. If using the Gradle plugin, this is swapped as the base class via bytecode transformation.
*/
@Generated("dagger.hilt.android.processor.internal.androidentrypoint.ApplicationGenerator")
public abstract class Hilt_OpenClawApp extends Application implements GeneratedComponentManagerHolder {
private boolean injected = false;
private final ApplicationComponentManager componentManager = new ApplicationComponentManager(new ComponentSupplier() {
@Override
public Object get() {
return DaggerOpenClawApp_HiltComponents_SingletonC.builder()
.applicationContextModule(new ApplicationContextModule(Hilt_OpenClawApp.this)).build();
}
});
@Override
public final ApplicationComponentManager componentManager() {
return componentManager;
}
@Override
public final Object generatedComponent() {
return this.componentManager().generatedComponent();
}
@CallSuper
@Override
public void onCreate() {
hiltInternalInject();
super.onCreate();
}
protected void hiltInternalInject() {
if (!injected) {
injected = true;
// This is a known unsafe cast, but is safe in the only correct use case:
// OpenClawApp extends Hilt_OpenClawApp
((OpenClawApp_GeneratedInjector) generatedComponent()).injectOpenClawApp(UnsafeCasts.<OpenClawApp>unsafeCast(this));
}
}
}
package com.nexlab.openclaw.node;
import dagger.hilt.InstallIn;
import dagger.hilt.codegen.OriginatingElement;
import dagger.hilt.components.SingletonComponent;
import dagger.hilt.internal.GeneratedEntryPoint;
import javax.annotation.processing.Generated;
@OriginatingElement(
topLevelClass = OpenClawApp.class
)
@GeneratedEntryPoint
@InstallIn(SingletonComponent.class)
@Generated("dagger.hilt.android.processor.internal.androidentrypoint.InjectorEntryPointGenerator")
public interface OpenClawApp_GeneratedInjector {
void injectOpenClawApp(OpenClawApp openClawApp);
}
package com.nexlab.openclaw.node;
import com.nexlab.openclaw.node.di.AppModule;
import com.nexlab.openclaw.node.ui.MainActivity_GeneratedInjector;
import dagger.Binds;
import dagger.Component;
import dagger.Module;
import dagger.Subcomponent;
import dagger.hilt.android.components.ActivityComponent;
import dagger.hilt.android.components.ActivityRetainedComponent;
import dagger.hilt.android.components.FragmentComponent;
import dagger.hilt.android.components.ServiceComponent;
import dagger.hilt.android.components.ViewComponent;
import dagger.hilt.android.components.ViewModelComponent;
import dagger.hilt.android.components.ViewWithFragmentComponent;
import dagger.hilt.android.flags.FragmentGetContextFix;
import dagger.hilt.android.flags.HiltWrapper_FragmentGetContextFix_FragmentGetContextFixModule;
import dagger.hilt.android.internal.builders.ActivityComponentBuilder;
import dagger.hilt.android.internal.builders.ActivityRetainedComponentBuilder;
import dagger.hilt.android.internal.builders.FragmentComponentBuilder;
import dagger.hilt.android.internal.builders.ServiceComponentBuilder;
import dagger.hilt.android.internal.builders.ViewComponentBuilder;
import dagger.hilt.android.internal.builders.ViewModelComponentBuilder;
import dagger.hilt.android.internal.builders.ViewWithFragmentComponentBuilder;
import dagger.hilt.android.internal.lifecycle.DefaultViewModelFactories;
import dagger.hilt.android.internal.lifecycle.HiltViewModelFactory;
import dagger.hilt.android.internal.lifecycle.HiltWrapper_DefaultViewModelFactories_ActivityModule;
import dagger.hilt.android.internal.lifecycle.HiltWrapper_HiltViewModelFactory_ActivityCreatorEntryPoint;
import dagger.hilt.android.internal.lifecycle.HiltWrapper_HiltViewModelFactory_ViewModelModule;
import dagger.hilt.android.internal.managers.ActivityComponentManager;
import dagger.hilt.android.internal.managers.FragmentComponentManager;
import dagger.hilt.android.internal.managers.HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint;
import dagger.hilt.android.internal.managers.HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedLifecycleEntryPoint;
import dagger.hilt.android.internal.managers.HiltWrapper_ActivityRetainedComponentManager_LifecycleModule;
import dagger.hilt.android.internal.managers.ServiceComponentManager;
import dagger.hilt.android.internal.managers.ViewComponentManager;
import dagger.hilt.android.internal.modules.ApplicationContextModule;
import dagger.hilt.android.internal.modules.HiltWrapper_ActivityModule;
import dagger.hilt.android.scopes.ActivityRetainedScoped;
import dagger.hilt.android.scopes.ActivityScoped;
import dagger.hilt.android.scopes.FragmentScoped;
import dagger.hilt.android.scopes.ServiceScoped;
import dagger.hilt.android.scopes.ViewModelScoped;
import dagger.hilt.android.scopes.ViewScoped;
import dagger.hilt.components.SingletonComponent;
import dagger.hilt.internal.GeneratedComponent;
import dagger.hilt.migration.DisableInstallInCheck;
import javax.annotation.processing.Generated;
import javax.inject.Singleton;
@Generated("dagger.hilt.processor.internal.root.RootProcessor")
public final class OpenClawApp_HiltComponents {
private OpenClawApp_HiltComponents() {
}
@Module(
subcomponents = ServiceC.class
)
@DisableInstallInCheck
@Generated("dagger.hilt.processor.internal.root.RootProcessor")
abstract interface ServiceCBuilderModule {
@Binds
ServiceComponentBuilder bind(ServiceC.Builder builder);
}
@Module(
subcomponents = ActivityRetainedC.class
)
@DisableInstallInCheck
@Generated("dagger.hilt.processor.internal.root.RootProcessor")
abstract interface ActivityRetainedCBuilderModule {
@Binds
ActivityRetainedComponentBuilder bind(ActivityRetainedC.Builder builder);
}
@Module(
subcomponents = ActivityC.class
)
@DisableInstallInCheck
@Generated("dagger.hilt.processor.internal.root.RootProcessor")
abstract interface ActivityCBuilderModule {
@Binds
ActivityComponentBuilder bind(ActivityC.Builder builder);
}
@Module(
subcomponents = ViewModelC.class
)
@DisableInstallInCheck
@Generated("dagger.hilt.processor.internal.root.RootProcessor")
abstract interface ViewModelCBuilderModule {
@Binds
ViewModelComponentBuilder bind(ViewModelC.Builder builder);
}
@Module(
subcomponents = ViewC.class
)
@DisableInstallInCheck
@Generated("dagger.hilt.processor.internal.root.RootProcessor")
abstract interface ViewCBuilderModule {
@Binds
ViewComponentBuilder bind(ViewC.Builder builder);
}
@Module(
subcomponents = FragmentC.class
)
@DisableInstallInCheck
@Generated("dagger.hilt.processor.internal.root.RootProcessor")
abstract interface FragmentCBuilderModule {
@Binds
FragmentComponentBuilder bind(FragmentC.Builder builder);
}
@Module(
subcomponents = ViewWithFragmentC.class
)
@DisableInstallInCheck
@Generated("dagger.hilt.processor.internal.root.RootProcessor")
abstract interface ViewWithFragmentCBuilderModule {
@Binds
ViewWithFragmentComponentBuilder bind(ViewWithFragmentC.Builder builder);
}
@Component(
modules = {
AppModule.class,
ApplicationContextModule.class,
HiltWrapper_FragmentGetContextFix_FragmentGetContextFixModule.class,
ActivityRetainedCBuilderModule.class,
ServiceCBuilderModule.class
}
)
@Singleton
public abstract static class SingletonC implements OpenClawApp_GeneratedInjector,
FragmentGetContextFix.FragmentGetContextFixEntryPoint,
HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint,
ServiceComponentManager.ServiceComponentBuilderEntryPoint,
SingletonComponent,
GeneratedComponent {
}
@Subcomponent
@ServiceScoped
public abstract static class ServiceC implements ServiceComponent,
GeneratedComponent {
@Subcomponent.Builder
abstract interface Builder extends ServiceComponentBuilder {
}
}
@Subcomponent(
modules = {
HiltWrapper_ActivityRetainedComponentManager_LifecycleModule.class,
ActivityCBuilderModule.class,
ViewModelCBuilderModule.class
}
)
@ActivityRetainedScoped
public abstract static class ActivityRetainedC implements ActivityRetainedComponent,
ActivityComponentManager.ActivityComponentBuilderEntryPoint,
HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedLifecycleEntryPoint,
GeneratedComponent {
@Subcomponent.Builder
abstract interface Builder extends ActivityRetainedComponentBuilder {
}
}
@Subcomponent(
modules = {
HiltWrapper_ActivityModule.class,
HiltWrapper_DefaultViewModelFactories_ActivityModule.class,
FragmentCBuilderModule.class,
ViewCBuilderModule.class
}
)
@ActivityScoped
public abstract static class ActivityC implements MainActivity_GeneratedInjector,
ActivityComponent,
DefaultViewModelFactories.ActivityEntryPoint,
HiltWrapper_HiltViewModelFactory_ActivityCreatorEntryPoint,
FragmentComponentManager.FragmentComponentBuilderEntryPoint,
ViewComponentManager.ViewComponentBuilderEntryPoint,
GeneratedComponent {
@Subcomponent.Builder
abstract interface Builder extends ActivityComponentBuilder {
}
}
@Subcomponent(
modules = HiltWrapper_HiltViewModelFactory_ViewModelModule.class
)
@ViewModelScoped
public abstract static class ViewModelC implements ViewModelComponent,
HiltViewModelFactory.ViewModelFactoriesEntryPoint,
GeneratedComponent {
@Subcomponent.Builder
abstract interface Builder extends ViewModelComponentBuilder {
}
}
@Subcomponent
@ViewScoped
public abstract static class ViewC implements ViewComponent,
GeneratedComponent {
@Subcomponent.Builder
abstract interface Builder extends ViewComponentBuilder {
}
}
@Subcomponent(
modules = ViewWithFragmentCBuilderModule.class
)
@FragmentScoped
public abstract static class FragmentC implements FragmentComponent,
DefaultViewModelFactories.FragmentEntryPoint,
ViewComponentManager.ViewWithFragmentComponentBuilderEntryPoint,
GeneratedComponent {
@Subcomponent.Builder
abstract interface Builder extends FragmentComponentBuilder {
}
}
@Subcomponent
@ViewScoped
public abstract static class ViewWithFragmentC implements ViewWithFragmentComponent,
GeneratedComponent {
@Subcomponent.Builder
abstract interface Builder extends ViewWithFragmentComponentBuilder {
}
}
}
package dagger.hilt.internal.aggregatedroot.codegen;
import dagger.hilt.android.HiltAndroidApp;
import dagger.hilt.internal.aggregatedroot.AggregatedRoot;
import javax.annotation.processing.Generated;
/**
* This class should only be referenced by generated code! This class aggregates information across multiple compilations.
*/
@AggregatedRoot(
root = "com.nexlab.openclaw.node.OpenClawApp",
rootPackage = "com.nexlab.openclaw.node",
originatingRoot = "com.nexlab.openclaw.node.OpenClawApp",
originatingRootPackage = "com.nexlab.openclaw.node",
rootAnnotation = HiltAndroidApp.class,
rootSimpleNames = "OpenClawApp",
originatingRootSimpleNames = "OpenClawApp"
)
@Generated("dagger.hilt.processor.internal.root.AggregatedRootGenerator")
public class _com_nexlab_openclaw_node_OpenClawApp {
}
package hilt_aggregated_deps;
import dagger.hilt.processor.internal.aggregateddeps.AggregatedDeps;
import javax.annotation.processing.Generated;
/**
* This class should only be referenced by generated code! This class aggregates information across multiple compilations.
*/
@AggregatedDeps(
components = "dagger.hilt.components.SingletonComponent",
entryPoints = "com.nexlab.openclaw.node.OpenClawApp_GeneratedInjector"
)
@Generated("dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsGenerator")
public class _com_nexlab_openclaw_node_OpenClawApp_GeneratedInjector {
}
package com.nexlab.openclaw.node;
import dagger.hilt.internal.aggregatedroot.codegen._com_nexlab_openclaw_node_OpenClawApp;
import dagger.hilt.internal.componenttreedeps.ComponentTreeDeps;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_components_ActivityComponent;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_components_ActivityRetainedComponent;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_components_FragmentComponent;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_components_ServiceComponent;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_components_ViewComponent;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_components_ViewModelComponent;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_components_ViewWithFragmentComponent;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_internal_builders_ActivityComponentBuilder;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_internal_builders_ActivityRetainedComponentBuilder;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_internal_builders_FragmentComponentBuilder;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_internal_builders_ServiceComponentBuilder;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_internal_builders_ViewComponentBuilder;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_internal_builders_ViewModelComponentBuilder;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_android_internal_builders_ViewWithFragmentComponentBuilder;
import dagger.hilt.processor.internal.definecomponent.codegen._dagger_hilt_components_SingletonComponent;
import hilt_aggregated_deps._com_nexlab_openclaw_node_OpenClawApp_GeneratedInjector;
import hilt_aggregated_deps._com_nexlab_openclaw_node_di_AppModule;
import hilt_aggregated_deps._com_nexlab_openclaw_node_ui_MainActivity_GeneratedInjector;
import hilt_aggregated_deps._dagger_hilt_android_flags_FragmentGetContextFix_FragmentGetContextFixEntryPoint;
import hilt_aggregated_deps._dagger_hilt_android_flags_HiltWrapper_FragmentGetContextFix_FragmentGetContextFixModule;
import hilt_aggregated_deps._dagger_hilt_android_internal_lifecycle_DefaultViewModelFactories_ActivityEntryPoint;
import hilt_aggregated_deps._dagger_hilt_android_internal_lifecycle_DefaultViewModelFactories_FragmentEntryPoint;
import hilt_aggregated_deps._dagger_hilt_android_internal_lifecycle_HiltViewModelFactory_ViewModelFactoriesEntryPoint;
import hilt_aggregated_deps._dagger_hilt_android_internal_lifecycle_HiltWrapper_DefaultViewModelFactories_ActivityModule;
import hilt_aggregated_deps._dagger_hilt_android_internal_lifecycle_HiltWrapper_HiltViewModelFactory_ActivityCreatorEntryPoint;
import hilt_aggregated_deps._dagger_hilt_android_internal_lifecycle_HiltWrapper_HiltViewModelFactory_ViewModelModule;
import hilt_aggregated_deps._dagger_hilt_android_internal_managers_ActivityComponentManager_ActivityComponentBuilderEntryPoint;
import hilt_aggregated_deps._dagger_hilt_android_internal_managers_FragmentComponentManager_FragmentComponentBuilderEntryPoint;
import hilt_aggregated_deps._dagger_hilt_android_internal_managers_HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint;
import hilt_aggregated_deps._dagger_hilt_android_internal_managers_HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedLifecycleEntryPoint;
import hilt_aggregated_deps._dagger_hilt_android_internal_managers_HiltWrapper_ActivityRetainedComponentManager_LifecycleModule;
import hilt_aggregated_deps._dagger_hilt_android_internal_managers_ServiceComponentManager_ServiceComponentBuilderEntryPoint;
import hilt_aggregated_deps._dagger_hilt_android_internal_managers_ViewComponentManager_ViewComponentBuilderEntryPoint;
import hilt_aggregated_deps._dagger_hilt_android_internal_managers_ViewComponentManager_ViewWithFragmentComponentBuilderEntryPoint;
import hilt_aggregated_deps._dagger_hilt_android_internal_modules_ApplicationContextModule;
import hilt_aggregated_deps._dagger_hilt_android_internal_modules_HiltWrapper_ActivityModule;
@ComponentTreeDeps(
rootDeps = _com_nexlab_openclaw_node_OpenClawApp.class,
defineComponentDeps = {
_dagger_hilt_android_components_ActivityComponent.class,
_dagger_hilt_android_components_ActivityRetainedComponent.class,
_dagger_hilt_android_components_FragmentComponent.class,
_dagger_hilt_android_components_ServiceComponent.class,
_dagger_hilt_android_components_ViewComponent.class,
_dagger_hilt_android_components_ViewModelComponent.class,
_dagger_hilt_android_components_ViewWithFragmentComponent.class,
_dagger_hilt_android_internal_builders_ActivityComponentBuilder.class,
_dagger_hilt_android_internal_builders_ActivityRetainedComponentBuilder.class,
_dagger_hilt_android_internal_builders_FragmentComponentBuilder.class,
_dagger_hilt_android_internal_builders_ServiceComponentBuilder.class,
_dagger_hilt_android_internal_builders_ViewComponentBuilder.class,
_dagger_hilt_android_internal_builders_ViewModelComponentBuilder.class,
_dagger_hilt_android_internal_builders_ViewWithFragmentComponentBuilder.class,
_dagger_hilt_components_SingletonComponent.class
},
aggregatedDeps = {
_com_nexlab_openclaw_node_OpenClawApp_GeneratedInjector.class,
_com_nexlab_openclaw_node_di_AppModule.class,
_com_nexlab_openclaw_node_ui_MainActivity_GeneratedInjector.class,
_dagger_hilt_android_flags_FragmentGetContextFix_FragmentGetContextFixEntryPoint.class,
_dagger_hilt_android_flags_HiltWrapper_FragmentGetContextFix_FragmentGetContextFixModule.class,
_dagger_hilt_android_internal_lifecycle_DefaultViewModelFactories_ActivityEntryPoint.class,
_dagger_hilt_android_internal_lifecycle_DefaultViewModelFactories_FragmentEntryPoint.class,
_dagger_hilt_android_internal_lifecycle_HiltViewModelFactory_ViewModelFactoriesEntryPoint.class,
_dagger_hilt_android_internal_lifecycle_HiltWrapper_DefaultViewModelFactories_ActivityModule.class,
_dagger_hilt_android_internal_lifecycle_HiltWrapper_HiltViewModelFactory_ActivityCreatorEntryPoint.class,
_dagger_hilt_android_internal_lifecycle_HiltWrapper_HiltViewModelFactory_ViewModelModule.class,
_dagger_hilt_android_internal_managers_ActivityComponentManager_ActivityComponentBuilderEntryPoint.class,
_dagger_hilt_android_internal_managers_FragmentComponentManager_FragmentComponentBuilderEntryPoint.class,
_dagger_hilt_android_internal_managers_HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint.class,
_dagger_hilt_android_internal_managers_HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedLifecycleEntryPoint.class,
_dagger_hilt_android_internal_managers_HiltWrapper_ActivityRetainedComponentManager_LifecycleModule.class,
_dagger_hilt_android_internal_managers_ServiceComponentManager_ServiceComponentBuilderEntryPoint.class,
_dagger_hilt_android_internal_managers_ViewComponentManager_ViewComponentBuilderEntryPoint.class,
_dagger_hilt_android_internal_managers_ViewComponentManager_ViewWithFragmentComponentBuilderEntryPoint.class,
_dagger_hilt_android_internal_modules_ApplicationContextModule.class,
_dagger_hilt_android_internal_modules_HiltWrapper_ActivityModule.class
}
)
public final class OpenClawApp_ComponentTreeDeps {
}
package dagger.hilt.internal.processedrootsentinel.codegen;
import dagger.hilt.internal.processedrootsentinel.ProcessedRootSentinel;
@ProcessedRootSentinel(
roots = "com.nexlab.openclaw.node.OpenClawApp"
)
public final class _com_nexlab_openclaw_node_OpenClawApp {
}
package com.nexlab.openclaw.node;
import dagger.hilt.InstallIn;
import dagger.hilt.codegen.OriginatingElement;
import dagger.hilt.components.SingletonComponent;
import dagger.hilt.internal.GeneratedEntryPoint;
import javax.annotation.processing.Generated;
@OriginatingElement(
topLevelClass = OpenClawApp.class
)
@GeneratedEntryPoint
@InstallIn(SingletonComponent.class)
@Generated("dagger.hilt.android.processor.internal.androidentrypoint.InjectorEntryPointGenerator")
public interface OpenClawApp_GeneratedInjector {
void injectOpenClawApp(OpenClawApp openClawApp);
}
package com.nexlab.openclaw.node.di;
import com.nexlab.openclaw.node.data.remote.NodeClient;
import dagger.internal.DaggerGenerated;
import dagger.internal.Factory;
import dagger.internal.Preconditions;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;
import javax.annotation.processing.Generated;
@ScopeMetadata("javax.inject.Singleton")
@QualifierMetadata
@DaggerGenerated
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://dagger.dev"
)
@SuppressWarnings({
"unchecked",
"rawtypes",
"KotlinInternal",
"KotlinInternalInJava"
})
public final class AppModule_ProvideNodeClientFactory implements Factory<NodeClient> {
@Override
public NodeClient get() {
return provideNodeClient();
}
public static AppModule_ProvideNodeClientFactory create() {
return InstanceHolder.INSTANCE;
}
public static NodeClient provideNodeClient() {
return Preconditions.checkNotNullFromProvides(AppModule.INSTANCE.provideNodeClient());
}
private static final class InstanceHolder {
private static final AppModule_ProvideNodeClientFactory INSTANCE = new AppModule_ProvideNodeClientFactory();
}
}
package com.nexlab.openclaw.node.di;
import android.content.Context;
import com.nexlab.openclaw.node.data.repository.SettingsRepository;
import dagger.internal.DaggerGenerated;
import dagger.internal.Factory;
import dagger.internal.Preconditions;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;
import javax.annotation.processing.Generated;
import javax.inject.Provider;
@ScopeMetadata("javax.inject.Singleton")
@QualifierMetadata("dagger.hilt.android.qualifiers.ApplicationContext")
@DaggerGenerated
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://dagger.dev"
)
@SuppressWarnings({
"unchecked",
"rawtypes",
"KotlinInternal",
"KotlinInternalInJava"
})
public final class AppModule_ProvideSettingsRepositoryFactory implements Factory<SettingsRepository> {
private final Provider<Context> contextProvider;
public AppModule_ProvideSettingsRepositoryFactory(Provider<Context> contextProvider) {
this.contextProvider = contextProvider;
}
@Override
public SettingsRepository get() {
return provideSettingsRepository(contextProvider.get());
}
public static AppModule_ProvideSettingsRepositoryFactory create(
Provider<Context> contextProvider) {
return new AppModule_ProvideSettingsRepositoryFactory(contextProvider);
}
public static SettingsRepository provideSettingsRepository(Context context) {
return Preconditions.checkNotNullFromProvides(AppModule.INSTANCE.provideSettingsRepository(context));
}
}
package com.nexlab.openclaw.node.service;
import android.content.Context;
import dagger.internal.DaggerGenerated;
import dagger.internal.Factory;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;
import javax.annotation.processing.Generated;
import javax.inject.Provider;
@ScopeMetadata("javax.inject.Singleton")
@QualifierMetadata("dagger.hilt.android.qualifiers.ApplicationContext")
@DaggerGenerated
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://dagger.dev"
)
@SuppressWarnings({
"unchecked",
"rawtypes",
"KotlinInternal",
"KotlinInternalInJava"
})
public final class AudioPlaybackService_Factory implements Factory<AudioPlaybackService> {
private final Provider<Context> contextProvider;
public AudioPlaybackService_Factory(Provider<Context> contextProvider) {
this.contextProvider = contextProvider;
}
@Override
public AudioPlaybackService get() {
return newInstance(contextProvider.get());
}
public static AudioPlaybackService_Factory create(Provider<Context> contextProvider) {
return new AudioPlaybackService_Factory(contextProvider);
}
public static AudioPlaybackService newInstance(Context context) {
return new AudioPlaybackService(context);
}
}
package com.nexlab.openclaw.node.service;
import android.content.Context;
import dagger.internal.DaggerGenerated;
import dagger.internal.Factory;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;
import javax.annotation.processing.Generated;
import javax.inject.Provider;
@ScopeMetadata("javax.inject.Singleton")
@QualifierMetadata("dagger.hilt.android.qualifiers.ApplicationContext")
@DaggerGenerated
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://dagger.dev"
)
@SuppressWarnings({
"unchecked",
"rawtypes",
"KotlinInternal",
"KotlinInternalInJava"
})
public final class CameraService_Factory implements Factory<CameraService> {
private final Provider<Context> contextProvider;
private final Provider<PermissionManager> permissionManagerProvider;
public CameraService_Factory(Provider<Context> contextProvider,
Provider<PermissionManager> permissionManagerProvider) {
this.contextProvider = contextProvider;
this.permissionManagerProvider = permissionManagerProvider;
}
@Override
public CameraService get() {
return newInstance(contextProvider.get(), permissionManagerProvider.get());
}
public static CameraService_Factory create(Provider<Context> contextProvider,
Provider<PermissionManager> permissionManagerProvider) {
return new CameraService_Factory(contextProvider, permissionManagerProvider);
}
public static CameraService newInstance(Context context, PermissionManager permissionManager) {
return new CameraService(context, permissionManager);
}
}
package com.nexlab.openclaw.node.service;
import android.content.Context;
import dagger.internal.DaggerGenerated;
import dagger.internal.Factory;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;
import javax.annotation.processing.Generated;
import javax.inject.Provider;
@ScopeMetadata("javax.inject.Singleton")
@QualifierMetadata("dagger.hilt.android.qualifiers.ApplicationContext")
@DaggerGenerated
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://dagger.dev"
)
@SuppressWarnings({
"unchecked",
"rawtypes",
"KotlinInternal",
"KotlinInternalInJava"
})
public final class ClipboardService_Factory implements Factory<ClipboardService> {
private final Provider<Context> contextProvider;
public ClipboardService_Factory(Provider<Context> contextProvider) {
this.contextProvider = contextProvider;
}
@Override
public ClipboardService get() {
return newInstance(contextProvider.get());
}
public static ClipboardService_Factory create(Provider<Context> contextProvider) {
return new ClipboardService_Factory(contextProvider);
}
public static ClipboardService newInstance(Context context) {
return new ClipboardService(context);
}
}
package com.nexlab.openclaw.node.service;
import android.content.Context;
import dagger.internal.DaggerGenerated;
import dagger.internal.Factory;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;
import javax.annotation.processing.Generated;
import javax.inject.Provider;
@ScopeMetadata("javax.inject.Singleton")
@QualifierMetadata("dagger.hilt.android.qualifiers.ApplicationContext")
@DaggerGenerated
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://dagger.dev"
)
@SuppressWarnings({
"unchecked",
"rawtypes",
"KotlinInternal",
"KotlinInternalInJava"
})
public final class MicrophoneService_Factory implements Factory<MicrophoneService> {
private final Provider<Context> contextProvider;
public MicrophoneService_Factory(Provider<Context> contextProvider) {
this.contextProvider = contextProvider;
}
@Override
public MicrophoneService get() {
return newInstance(contextProvider.get());
}
public static MicrophoneService_Factory create(Provider<Context> contextProvider) {
return new MicrophoneService_Factory(contextProvider);
}
public static MicrophoneService newInstance(Context context) {
return new MicrophoneService(context);
}
}
package com.nexlab.openclaw.node.service;
import android.content.Context;
import dagger.internal.DaggerGenerated;
import dagger.internal.Factory;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;
import javax.annotation.processing.Generated;
import javax.inject.Provider;
@ScopeMetadata("javax.inject.Singleton")
@QualifierMetadata("dagger.hilt.android.qualifiers.ApplicationContext")
@DaggerGenerated
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://dagger.dev"
)
@SuppressWarnings({
"unchecked",
"rawtypes",
"KotlinInternal",
"KotlinInternalInJava"
})
public final class PermissionManager_Factory implements Factory<PermissionManager> {
private final Provider<Context> contextProvider;
public PermissionManager_Factory(Provider<Context> contextProvider) {
this.contextProvider = contextProvider;
}
@Override
public PermissionManager get() {
return newInstance(contextProvider.get());
}
public static PermissionManager_Factory create(Provider<Context> contextProvider) {
return new PermissionManager_Factory(contextProvider);
}
public static PermissionManager newInstance(Context context) {
return new PermissionManager(context);
}
}
package com.nexlab.openclaw.node.service;
import android.content.Context;
import dagger.internal.DaggerGenerated;
import dagger.internal.Factory;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;
import javax.annotation.processing.Generated;
import javax.inject.Provider;
@ScopeMetadata("javax.inject.Singleton")
@QualifierMetadata("dagger.hilt.android.qualifiers.ApplicationContext")
@DaggerGenerated
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://dagger.dev"
)
@SuppressWarnings({
"unchecked",
"rawtypes",
"KotlinInternal",
"KotlinInternalInJava"
})
public final class UsageStatsService_Factory implements Factory<UsageStatsService> {
private final Provider<Context> contextProvider;
public UsageStatsService_Factory(Provider<Context> contextProvider) {
this.contextProvider = contextProvider;
}
@Override
public UsageStatsService get() {
return newInstance(contextProvider.get());
}
public static UsageStatsService_Factory create(Provider<Context> contextProvider) {
return new UsageStatsService_Factory(contextProvider);
}
public static UsageStatsService newInstance(Context context) {
return new UsageStatsService(context);
}
}
package com.nexlab.openclaw.node.ui;
import android.content.Context;
import androidx.activity.ComponentActivity;
import androidx.activity.contextaware.OnContextAvailableListener;
import androidx.lifecycle.ViewModelProvider;
import dagger.hilt.android.internal.lifecycle.DefaultViewModelFactories;
import dagger.hilt.android.internal.managers.ActivityComponentManager;
import dagger.hilt.internal.GeneratedComponentManagerHolder;
import dagger.hilt.internal.UnsafeCasts;
import java.lang.Object;
import java.lang.Override;
import javax.annotation.processing.Generated;
/**
* A generated base class to be extended by the @dagger.hilt.android.AndroidEntryPoint annotated class. If using the Gradle plugin, this is swapped as the base class via bytecode transformation.
*/
@Generated("dagger.hilt.android.processor.internal.androidentrypoint.ActivityGenerator")
public abstract class Hilt_MainActivity extends ComponentActivity implements GeneratedComponentManagerHolder {
private volatile ActivityComponentManager componentManager;
private final Object componentManagerLock = new Object();
private boolean injected = false;
Hilt_MainActivity() {
super();
_initHiltInternal();
}
Hilt_MainActivity(int contentLayoutId) {
super(contentLayoutId);
_initHiltInternal();
}
private void _initHiltInternal() {
addOnContextAvailableListener(new OnContextAvailableListener() {
@Override
public void onContextAvailable(Context context) {
inject();
}
});
}
@Override
public final Object generatedComponent() {
return this.componentManager().generatedComponent();
}
protected ActivityComponentManager createComponentManager() {
return new ActivityComponentManager(this);
}
@Override
public final ActivityComponentManager componentManager() {
if (componentManager == null) {
synchronized (componentManagerLock) {
if (componentManager == null) {
componentManager = createComponentManager();
}
}
}
return componentManager;
}
protected void inject() {
if (!injected) {
injected = true;
((MainActivity_GeneratedInjector) this.generatedComponent()).injectMainActivity(UnsafeCasts.<MainActivity>unsafeCast(this));
}
}
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
return DefaultViewModelFactories.getActivityFactory(this, super.getDefaultViewModelProviderFactory());
}
}
package com.nexlab.openclaw.node.ui;
import dagger.hilt.InstallIn;
import dagger.hilt.android.components.ActivityComponent;
import dagger.hilt.codegen.OriginatingElement;
import dagger.hilt.internal.GeneratedEntryPoint;
import javax.annotation.processing.Generated;
@OriginatingElement(
topLevelClass = MainActivity.class
)
@GeneratedEntryPoint
@InstallIn(ActivityComponent.class)
@Generated("dagger.hilt.android.processor.internal.androidentrypoint.InjectorEntryPointGenerator")
public interface MainActivity_GeneratedInjector {
void injectMainActivity(MainActivity mainActivity);
}
package com.nexlab.openclaw.node.ui;
import com.nexlab.openclaw.node.data.repository.SettingsRepository;
import dagger.MembersInjector;
import dagger.internal.DaggerGenerated;
import dagger.internal.InjectedFieldSignature;
import dagger.internal.QualifierMetadata;
import javax.annotation.processing.Generated;
import javax.inject.Provider;
@QualifierMetadata
@DaggerGenerated
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://dagger.dev"
)
@SuppressWarnings({
"unchecked",
"rawtypes",
"KotlinInternal",
"KotlinInternalInJava"
})
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final Provider<SettingsRepository> settingsRepositoryProvider;
public MainActivity_MembersInjector(Provider<SettingsRepository> settingsRepositoryProvider) {
this.settingsRepositoryProvider = settingsRepositoryProvider;
}
public static MembersInjector<MainActivity> create(
Provider<SettingsRepository> settingsRepositoryProvider) {
return new MainActivity_MembersInjector(settingsRepositoryProvider);
}
@Override
public void injectMembers(MainActivity instance) {
injectSettingsRepository(instance, settingsRepositoryProvider.get());
}
@InjectedFieldSignature("com.nexlab.openclaw.node.ui.MainActivity.settingsRepository")
public static void injectSettingsRepository(MainActivity instance,
SettingsRepository settingsRepository) {
instance.settingsRepository = settingsRepository;
}
}
package dagger.hilt.internal.aggregatedroot.codegen;
import dagger.hilt.android.HiltAndroidApp;
import dagger.hilt.internal.aggregatedroot.AggregatedRoot;
import javax.annotation.processing.Generated;
/**
* This class should only be referenced by generated code! This class aggregates information across multiple compilations.
*/
@AggregatedRoot(
root = "com.nexlab.openclaw.node.OpenClawApp",
rootPackage = "com.nexlab.openclaw.node",
originatingRoot = "com.nexlab.openclaw.node.OpenClawApp",
originatingRootPackage = "com.nexlab.openclaw.node",
rootAnnotation = HiltAndroidApp.class,
rootSimpleNames = "OpenClawApp",
originatingRootSimpleNames = "OpenClawApp"
)
@Generated("dagger.hilt.processor.internal.root.AggregatedRootGenerator")
public class _com_nexlab_openclaw_node_OpenClawApp {
}
package hilt_aggregated_deps;
import dagger.hilt.processor.internal.aggregateddeps.AggregatedDeps;
import javax.annotation.processing.Generated;
/**
* This class should only be referenced by generated code! This class aggregates information across multiple compilations.
*/
@AggregatedDeps(
components = "dagger.hilt.components.SingletonComponent",
entryPoints = "com.nexlab.openclaw.node.OpenClawApp_GeneratedInjector"
)
@Generated("dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsGenerator")
public class _com_nexlab_openclaw_node_OpenClawApp_GeneratedInjector {
}
package hilt_aggregated_deps;
import dagger.hilt.processor.internal.aggregateddeps.AggregatedDeps;
import javax.annotation.processing.Generated;
/**
* This class should only be referenced by generated code! This class aggregates information across multiple compilations.
*/
@AggregatedDeps(
components = "dagger.hilt.components.SingletonComponent",
modules = "com.nexlab.openclaw.node.di.AppModule"
)
@Generated("dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsGenerator")
public class _com_nexlab_openclaw_node_di_AppModule {
}
package hilt_aggregated_deps;
import dagger.hilt.processor.internal.aggregateddeps.AggregatedDeps;
import javax.annotation.processing.Generated;
/**
* This class should only be referenced by generated code! This class aggregates information across multiple compilations.
*/
@AggregatedDeps(
components = "dagger.hilt.android.components.ActivityComponent",
entryPoints = "com.nexlab.openclaw.node.ui.MainActivity_GeneratedInjector"
)
@Generated("dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsGenerator")
public class _com_nexlab_openclaw_node_ui_MainActivity_GeneratedInjector {
}
{"hilt-android-compiler-2.48.1.jar (com.google.dagger:hilt-android-compiler:2.48.1)":"KSP_PROCESSOR","dagger-compiler-2.48.1.jar (com.google.dagger:dagger-compiler:2.48.1)":"KSP_PROCESSOR"}
\ No newline at end of file
#- File Locator -
listingFile=../../../outputs/apk/debug/output-metadata.json
appMetadataVersion=1.1
androidGradlePluginVersion=8.2.0
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment