The QSL4A codebase is located at /qsl4a/src/main/java/org/qpython/qsl4a/ and is organized into the following packages:
| Package | Purpose |
|---|---|
org.qpython.qsl4a (root) |
Main entry points (QSL4APP, QPyScriptService, QSL4AScript) |
org.qpython.qsl4a.codec |
Base64 encoding/decoding for data serialization |
org.qpython.qsl4a.facade |
Android API facades (30+ classes) |
org.qpython.qsl4a.facade.ui |
UI-related facade components |
org.qpython.qsl4a.facade.usb |
USB serial communication facades |
org.qpython.qsl4a.qsl4a |
Core infrastructure |
org.qpython.qsl4a.qsl4a.event |
Event system |
org.qpython.qsl4a.qsl4a.exception |
Exception types |
org.qpython.qsl4a.qsl4a.future |
Async activity handling |
org.qpython.qsl4a.qsl4a.interpreter |
Interpreter management |
org.qpython.qsl4a.qsl4a.jsonrpc |
JSON-RPC mechanism |
org.qpython.qsl4a.qsl4a.language |
Language support |
org.qpython.qsl4a.qsl4a.rpc |
RPC annotations and descriptors |
org.qpython.qsl4a.qsl4a.trigger |
Event trigger system |
org.qpython.qsl4a.qsl4a.util |
Utility classes |
Purpose: Application class that initializes the QSL4A runtime environment.
Key Methods:
initQSL4APP()- Initializes interpreter configuration and starts discovering interpretersgetTaskExecutor()->FutureActivityTaskExecutor- Returns the task executorgetInterpreterConfiguration()->InterpreterConfiguration- Returns interpreter configgetTriggerRepository()->TriggerRepository- Returns the trigger repositoryreadyToStart()->boolean- Blocks until configuration is updated
Purpose: Android Service that hosts the JSON-RPC server for script execution.
Key Methods:
onCreate()- Starts the service and initializes the proxyonDestroy()- Shuts down the proxy and RPC serveronBind(Intent intent)->IBinder- Returns binder for service connectiononStartCommand(Intent intent, int flags, int startId)->int- Returns START_STICKYstart(Context context)- Static method to start the servicestop(Context context)- Static method to stop the servicestartToast(Context context)- Shows toast when service starts
Purpose: Utility class for script file handling.
Key Methods:
getFileName(Context context)->String- Returns the main script filename (default: "main.py")getFileExtension(Context context)->String- Returns file extension (e.g., ".py")
Purpose: Central proxy class that manages the RPC server and facade factories.
Key Methods:
AndroidProxy(Service service, Intent intent)- Constructor; creates JSON-RPC server with secret UUIDgetAddress()->InetSocketAddress- Returns server addressstartLocal()/startLocal(int port)- Starts RPC server on localhostshutdown()- Shuts down the RPC servergetSecret()->String- Returns the authentication secretgetRpcReceiverManagerFactory()->RpcReceiverManagerFactory- Returns the facade factory
Purpose: Abstract base class for TCP socket servers handling concurrent connections.
Key Methods:
startLocal(int port)->InetSocketAddress- Starts server on localhoststartPublic(int port)->InetSocketAddress- Starts server on public interfacestartAllInterfaces(int port)->InetSocketAddress- Starts server on all interfacesshutdown()- Stops the server and closes all connectionsgetNumberOfConnections()->int- Returns active connection countaddObserver(SimpleServerObserver)/removeObserver(SimpleServerObserver)- Observer pattern
Abstract Methods:
handleConnection(Socket socket)- Subclasses implement to handle client connections
All facades extend RpcReceiver and are managed by FacadeManager. They expose Android functionality via RPC-annotated methods.
Purpose: Manages all facade instances and handles RPC invocation with SDK version checking.
Key Methods:
FacadeManager(int sdkLevel, Service service, Intent intent, Collection<Class<? extends RpcReceiver>> classList)- ConstructorgetSdkLevel()->int- Returns Android SDK levelgetService()->Service- Returns the Android servicegetIntent()->Intent- Returns the launch intentinvoke(Class<? extends RpcReceiver> clazz, Method method, Object[] args)->Object- Invokes RPC with deprecation/minSdk checksgetReceiver(Class<T> clazz)->T- Gets or creates a facade instance
Purpose: Registry of all available facade classes.
Registered Facades (30 total):
AndroidFacade- Core Android operationsApplicationManagerFacade- App managementCameraFacade- Camera accessCommonIntentsFacade- Common Android intentsContactsFacade- Contacts accessEventFacade- Event queue managementLocationFacade- GPS/LocationPhoneFacade- Phone operationsMediaRecorderFacade- Audio recordingSensorManagerFacade- Device sensorsSettingsFacade- System settingsSmsFacade- SMS operationsSpeechRecognitionFacade- Voice inputToneGeneratorFacade- DTMF tonesWakeLockFacade- Power managementWifiFacade- WiFi operationsUiFacade- UI operationsBatteryManagerFacade- Battery infoMediaPlayerFacade- Media playbackPreferencesFacade- Shared preferencesQPyInterfaceFacade- QPython-specificUSBHostSerialFacade- USB serialCipherFacade- CryptographyTextToSpeechFacade- TTSBluetoothFacade- BluetoothSignalStrengthFacade- Signal infoWebCamFacade- CameraFloatViewFacade- Overlay viewsDocumentFileFacade- Document accessHarmonyOsFacade- HarmonyOS compatibilityFtpFacade- FTP serverAccessibilityFacade- Accessibility services
Purpose: Main facade providing core Android functionality.
Key RPC Methods:
setClipboard(String text)/getClipboard()->String- Clipboard operationsstartActivity(String action, String uri, ...)- Start activitiesstartActivityForResult(String action, ...)->Intent- Activity with resultsendBroadcast(String action, ...)- Send broadcastsmakeIntent(String action, ...)->Intent- Create intentsmakeToast(String message, int length, ...)- Show toast notificationsnotify(String title, String message, String uri, ...)- Show persistent notificationsgetNetworkStatus()->boolean- Check networkgetIntent()->Object- Get launch intentgetPackageVersion(String packageName)->String- Get package versionenvironment()->Map<String, Object>- Environment infogetConstants(String classname)->Bundle- Get class constantsvibrate(int duration)- Vibrate device
Purpose: Event queue management for async event handling.
Key RPC Methods:
eventClearBuffer()- Clears all events from buffereventPoll(int number_of_events)->List<Event>- Returns and removes oldest n eventseventWaitFor(String eventName, Integer timeout)->Event- Blocks until event occurseventWait(Integer timeout)->Event- Blocks until any event occurseventPost(String name, String data, Boolean enqueue)- Post event to queuestartEventDispatcher(int port)->int- Opens socket for event streamingstopEventDispatcher()- Stops event servereventRegisterForBroadcast(String category, Boolean enqueue)->boolean- Register broadcast listenereventUnregisterForBroadcast(String category)- Unregister broadcast listenereventGetBrodcastCategories()->Set<String>- Get registered categories
Purpose: Access device sensors (accelerometer, magnetometer, light, gyroscope, etc.).
Key RPC Methods:
startSensingTimed(int sensorNumber, int delayTime)- Starts sensor data collectionstartSensingThreshold(int sensorNumber, int threshold, int axis)- Threshold-based sensingreadSensors()->Bundle- Returns most recent sensor datastopSensing()- Stops sensor collectionsensorsGetAccuracy()->Integer- Get sensor accuracysensorsGetLight()->Float- Get light levelsensorsReadAccelerometer()->List<Float>- [x, y, z] accelerationsensorsReadMagnetometer()->List<Float>- [x, y, z] magnetic fieldsensorsReadGyroscope()->List<Float>- [x, y, z] angular speedsensorsReadOrientation()->List<Double>- [azimuth, pitch, roll]sensorsGetStepCounter()->Integer- Step count
Purpose: GPS and network location services.
Key RPC Methods:
startLocating(int minUpdateTime, int minUpdateDistance, boolean updateGnssStatus)- Start location updatesreadLocation()->Map<String, JSONObject>- Get current location by providerreadGnssStatus()->JSONArray- Get GNSS satellite status (Android 8+)stopLocating()- Stop location updatesgetLastKnownLocation()->Map<String, JSONObject>- Get last known locationgeocode(double latitude, double longitude, int maxResults)->JSONObject[]- Reverse geocodelocationProviders()->List<String>- Get available providerslocationProviderEnabled(String provider)->boolean- Check if provider enabled
JsonRpcServer (extends SimpleServer)
|
+-- handleConnection(Socket socket)
| |
| +-- Reads JSON requests line-by-line
| +-- First RPC must be _authenticate with secret
| +-- Looks up MethodDescriptor by method name
| +-- Invokes method and returns JsonRpcResult
|
+-- RpcReceiverManagerFactory
|
+-- FacadeManagerFactory
|
+-- Creates FacadeManager instances
+-- Each FacadeManager manages multiple RpcReceivers (Facades)
Purpose: TCP-based JSON-RPC server that handles client connections.
Key Methods:
JsonRpcServer(RpcReceiverManagerFactory managerFactory, String handshake)- ConstructorhandleConnection(Socket socket)- Processes JSON-RPC requestsshutdown()- Notifies all receivers and stops server
Request Format:
{"id": 1, "method": "methodName", "params": [arg1, arg2]}Response Format:
{"id": 1, "result": {...}, "error": null}Purpose: Base class managing RPC receivers (facades) and method lookup.
Key Methods:
RpcReceiverManager(Collection<Class<? extends RpcReceiver>> classList)- Initializes receivers and collects RPC methodsgetReceiver(Class<T> clazz)->T- Gets or lazily creates facade instancegetMethodDescriptor(String methodName)->MethodDescriptor- Looks up RPC methodinvoke(Class<? extends RpcReceiver> clazz, Method method, Object[] args)->Object- Invokes method via reflectionshutdown()- Calls shutdown on all receivers
Purpose: Abstract base class for all facades.
Methods:
RpcReceiver(RpcReceiverManager manager)- Constructor; stores manager referenceshutdown()- Abstract; facades implement cleanup
Purpose: Utility class for building JSON-RPC response objects.
Static Methods:
empty(int id)->JSONObject- Creates empty result responseresult(int id, Object data)->JSONObject- Creates success responseerror(int id, Throwable t)->JSONObject- Creates error response
Purpose: Converts Java objects to JSON for RPC responses.
Key Methods:
build(Object data)->Object- Converts Java object to JSON-compatible typebuildBundleItem(Object data)->Object- Handles Bundle, Uri, byte[] special casesbuildJsonMap(Map<String, ?> map)->JSONObject- Converts Map to JSONObjectbuildJsonList(List<?> list)->JSONArray- Converts List to JSONArraybuildJsonIntent(Intent intent)->JSONObject- Converts Intent to JSONbuildJsonEvent(Event event)->JSONObject- Converts Event to JSON
Supported Type Conversions:
null->JSONObject.NULLInteger, Long, Double-> primitive valuesString, Boolean-> as-isJSONObject, JSONArray-> as-isList<?>->JSONArraySet<?>->JSONArrayMap<?, ?>->JSONObjectIntent->{"data", "type", "extras", "categories", "action", "packagename", "classname", "flags"}Bundle->JSONObjectwith special markers (\0uri\0,\0byte\0)Event->{"name", "data", "time"}
Purpose: Describes an RPC method, handles parameter conversion, and invokes methods.
Key Methods:
collectFrom(Class<? extends RpcReceiver> clazz)->Collection<MethodDescriptor>- Static; collects @Rpc-annotated methodsinvoke(RpcReceiverManager manager, JSONArray parameters)->Object- Invokes RPC with parameter conversionconvertParameter(JSONArray parameters, int index, Type type)->Object- Converts JSON param to Java typebuildIntent(JSONObject jsonObject)->Intent- Builds Intent from JSONgetName()->String- Returns RPC name (or @RpcName value)getHelp()->String- Generates help text from annotations
Parameter Type Conversions:
Boolean.class- from JSON boolean or integer (0/1)Long.class- from JSON longDouble.class- from JSON doubleInteger.class- from JSON intIntent.class- from JSONObject usingbuildIntent()- Other types - direct cast from JSON
Purpose: Marks a method as an RPC endpoint.
Attributes:
description()->String- Brief description of the functionreturns()->String- Description of return value (default: "")
Purpose: Documents RPC parameters.
Attributes:
name()->String- Formal parameter namedescription()->String- Parameter description (default: "")
Purpose: Specifies default value for optional parameters.
Attributes:
value()->String- Default value as stringconverter()->Class<? extends Converter>- Type converter (default: Converter.class)
Purpose: Marks parameter as optional with null default.
Purpose: Overrides the RPC method name.
Attributes:
name()->String- Custom RPC name
Purpose: Marks RPC as deprecated.
Attributes:
value()->String- Replacement method namerelease()->String- Release version when deprecated
Purpose: Specifies minimum Android SDK version required.
Attributes:
value()->int- Minimum SDK level
Purpose: Indicates RPC starts an event stream.
Attributes:
value()->String- Event name
Purpose: Indicates RPC stops an event stream.
Attributes:
value()->String- Event name
Purpose: Represents a language interpreter with execution parameters.
Key Methods:
buildFromMaps(Map<String, String> data, Map<String, String> env, Map<String, String> args)->Interpreter- Static factorygetName()->String- Interpreter name (e.g., "python")getNiceName()->String- Display namegetExtension()->String- File extension (e.g., ".py")getBinary()->File- Path to interpreter binarygetScriptCommand()->String- Command template for script executiongetInteractiveCommand()->String- Command for interactive modehasInteractiveMode()->boolean- Whether interactive mode supportedgetArguments()->List<String>- CLI argumentsgetEnvironmentVariables()->Map<String, String>- Environment variablesgetLanguage()->Language- Associated language objectgetRpcText(String content, MethodDescriptor rpc, String[] values)->String- Generates RPC call codeisInstalled()->boolean- Whether binary exists
Purpose: Discovers and manages installed interpreters via Android package intents.
Key Methods:
startDiscovering()/startDiscovering(String mime)- Starts interpreter discoveryisDiscoveryComplete()->boolean- Whether discovery finishedregisterObserver(ConfigurationObserver observer)- Register for config changesgetSupportedInterpreters()->List<? extends Interpreter>- All known interpretersgetInstalledInterpreters()->List<Interpreter>- Only installed onesgetInteractiveInterpreters()->List<Interpreter>- Those with interactive modegetInterpreterByName(String name)->Interpreter- Find by namegetInterpreterForScript(String scriptName)->Interpreter- Find by file extension
Discovery Mechanism:
- Queries package manager for activities handling
InterpreterConstants.MIME + extension - Reads interpreter properties from ContentProvider
- Broadcasts
ACTION_INTERPRETER_ADDED/ACTION_INTERPRETER_REMOVED
Purpose: Metadata about an interpreter version.
Attributes:
getVersion()->String- Version stringgetName()->String- Interpreter nameisInstalled()->boolean- Installation status
Purpose: Registry mapping file extensions to Language classes.
Supported Languages:
| Extension | Language Class |
|---|---|
.html |
HtmlLanguage |
.bsh |
BeanShellLanguage |
.js |
JavaScriptLanguage |
.lua |
LuaLanguage |
.pl |
PerlLanguage |
.py |
PythonLanguage |
.rb |
RubyLanguage |
.tcl |
TclLanguage |
.php |
PhpLanguage |
.sl |
SleepLanguage |
.nut |
SquirrelLanguage |
Purpose: Base class for language-specific code generation.
Key Methods:
getContentTemplate()->String- Template for new scriptsgetImportStatement()->String- Import statement (overridden per language)getRpcReceiverDeclaration(String rpcReceiver)->String- RPC receiver instantiationgetDefaultRpcReceiver()->String- Default receiver name (default: "droid")getRpcText(String content, MethodDescriptor rpc, String[] values)->String- Generates method callautoClose(char token)->String- Returns closing token for auto-complete
Purpose: Python-specific code generation.
Generated Template:
import android
droid = android.Android()Purpose: Persistent storage and management of event triggers.
Key Methods:
put(Trigger trigger)- Adds trigger and ensures TriggerService runningremove(Trigger trigger)- Removes triggergetAllTriggers()->Multimap<String, Trigger>- All triggers by event nameisEmpty()->boolean- Whether any triggers existaddObserver(TriggerRepositoryObserver observer)- Register for changesbootstrapObserver(TriggerRepositoryObserver observer)- Register and notify of existing triggersremoveObserver(TriggerRepositoryObserver observer)- Unregister
Persistence:
- Serializes to Base64-encoded object stream
- Stores in SharedPreferences under key "TRIGGERS"
Purpose: Interface for event-driven script execution.
Methods:
handleEvent(Event event, Context context)- Called when trigger event occursgetEventName()->String- Event name this trigger listens for
Purpose: Trigger implementation that launches a script file.
Key Methods:
ScriptTrigger(String eventName, File script)- ConstructorhandleEvent(Event event, Context context)- Starts script via IntentBuildersgetEventName()->String- Returns registered event namegetScript()->File- Returns script file
Purpose: Immutable event object for the event queue.
Attributes:
mName- Event namemData- Event data (any object)mCreationTime- Creation timestamp (milliseconds * 1000)
Key Methods:
Event(String name, Object data)- ConstructorgetName()/setName(String name)- Name accessorgetData()/setData(Object data)- Data accessorgetCreationTime()->double- TimestampnameEquals(String name)->boolean- Name comparison
Purpose: Interface for event notification.
Methods:
onEventReceived(Event event)- Called when event occurs
Purpose: TCP server that streams events to connected clients.
Key Methods:
EventServer(int port)- Constructor; starts server on specified portgetAddress()->InetSocketAddress- Server addressonEventReceived(Event event)- Broadcasts event to all listenersshutdown()- Notifies listeners and stops server
Purpose: Blocking future for async operation results.
Key Methods:
set(T result)- Sets result and unblocks waitersget()->T- Blocks until result availableget(long timeout, TimeUnit unit)->T- Blocks with timeoutisDone()->boolean- Whether result availablecancel(boolean mayInterruptIfRunning)->boolean- Always returns false
Purpose: Activity lifecycle wrapper for async UI operations.
Key Methods:
onCreate()/onStart()/onResume()/onPause()/onStop()/onDestroy()- Lifecycle callbacksonActivityResult(int requestCode, int resultCode, Intent data)- Handle activity resultsetActivity(Activity activity)/getActivity()->Activity- Activity accesssetTaskDescription(String title)- Set task description (for recent apps)setResult(T result)- Set the task resultgetResult()->T- Get the result (blocks)finish()- Finish the activitystartActivity(Intent intent)/startActivityForResult(Intent intent, int requestCode)- Start activities
Purpose: Executes FutureActivityTask instances on the main thread.
Key Methods:
execute(FutureActivityTask<T> task)- Execute task with activity lifecycle
/qsl4a/src/main/java/org/qpython/qsl4a/
├── QSL4APP.java # Application class
├── QPyScriptService.java # Android Service (RPC server host)
├── QSL4AScript.java # Script file utilities
├── codec/ # Base64 encoding
├── facade/ # Android API facades (30+ classes)
│ ├── AndroidFacade.java # Core Android operations
│ ├── EventFacade.java # Event queue management
│ ├── LocationFacade.java # GPS/Location
│ ├── SensorManagerFacade.java # Device sensors
│ ├── UiFacade.java # UI operations
│ └── ... (25+ more facades)
├── qsl4a/
│ ├── AndroidProxy.java # Central proxy/RPC server
│ ├── SimpleServer.java # TCP socket server base
│ ├── Constants.java # Intent/action constants
│ ├── event/
│ │ └── Event.java # Event data class
│ ├── exception/
│ │ └── Sl4aException.java # Base exception
│ ├── future/
│ │ ├── FutureResult.java # Async result holder
│ │ ├── FutureActivityTask.java # Activity lifecycle wrapper
│ │ └── FutureActivityTaskExecutor.java
│ ├── interpreter/
│ │ ├── Interpreter.java # Interpreter descriptor
│ │ ├── InterpreterConfiguration.java # Interpreter discovery
│ │ └── Language.java # Base language class
│ ├── jsonrpc/
│ │ ├── JsonRpcServer.java # JSON-RPC TCP server
│ │ ├── RpcReceiver.java # Base facade class
│ │ ├── RpcReceiverManager.java # Manages facades
│ │ ├── RpcReceiverManagerFactory.java
│ │ ├── JsonRpcResult.java # Response builder
│ │ └── JsonBuilder.java # JSON serialization
│ ├── language/
│ │ ├── Language.java # Base language
│ │ ├── PythonLanguage.java # Python-specific
│ │ └── SupportedLanguages.java # Extension registry
│ ├── rpc/
│ │ ├── Rpc.java # @Rpc annotation
│ │ ├── RpcParameter.java # @RpcParameter annotation
│ │ ├── RpcDefault.java # @RpcDefault annotation
│ │ ├── RpcOptional.java # @RpcOptional annotation
│ │ ├── RpcName.java # @RpcName annotation
│ │ ├── RpcDeprecated.java # @RpcDeprecated annotation
│ │ ├── RpcMinSdk.java # @RpcMinSdk annotation
│ │ ├── RpcStartEvent.java # @RpcStartEvent annotation
│ │ ├── RpcStopEvent.java # @RpcStopEvent annotation
│ │ └── MethodDescriptor.java # RPC method descriptor
│ ├── trigger/
│ │ ├── Trigger.java # Trigger interface
│ │ ├── ScriptTrigger.java # Script launch trigger
│ │ └── TriggerRepository.java # Persistent trigger storage
│ └── util/ # Utilities
- Script is launched (via Intent or direct start)
QPyScriptServicestarts viaAndroidProxyJsonRpcServerstarts on localhost with random port- Script connects via TCP socket
- First RPC must be
_authenticate(secret) - Script calls RPCs like
droid.makeToast("Hello") JsonRpcServerlooks upMethodDescriptorviaRpcReceiverManagerMethodDescriptor.invoke()converts JSON params to Java types- Facade method is invoked via reflection
- Result is converted back to JSON via
JsonBuilder - Response sent back to client
- Facade calls
eventPost("sensors", data)or similar EventFacade.postEvent()createsEventobject- Event added to
ConcurrentLinkedQueue<Event>(max 1024) - Named event observers are notified
- Global event observers are notified
EventServerbroadcasts to all connected TCP clients
TriggerRepository.put(trigger)stores trigger- Trigger serialized to SharedPreferences
- When matching event occurs,
Trigger.handleEvent()is called ScriptTriggerstarts script viaIntentBuilders.buildStartInBackgroundIntent()
| Facade Class | Purpose |
|---|---|
AccessibilityFacade |
Accessibility services |
ActivityResultFacade |
Activity result handling |
AndroidFacade |
Core Android operations |
ApplicationManagerFacade |
Application management |
BatteryManagerFacade |
Battery status |
BluetoothFacade |
Bluetooth operations |
CameraFacade |
Camera access |
CipherFacade |
Cryptography/Encryption |
CommonIntentsFacade |
Common Android intents |
ContactsFacade |
Contacts access |
DocumentFileFacade |
Document file access |
EventFacade |
Event queue management |
EventServer |
TCP event streaming |
FloatViewFacade |
Overlay/floating views |
FtpFacade |
FTP server |
HarmonyOsFacade |
HarmonyOS compatibility |
LocationFacade |
GPS/Location |
MediaPlayerFacade |
Media playback |
MediaRecorderFacade |
Audio/video recording |
MjpegServer |
MJPEG streaming |
PhoneFacade |
Phone operations |
PreferencesFacade |
Shared preferences |
QPyInterfaceFacade |
QPython-specific interface |
SensorManagerFacade |
Device sensors |
SettingsFacade |
System settings |
SignalStrengthFacade |
Signal strength |
SmsFacade |
SMS operations |
SpeechRecognitionFacade |
Speech recognition |
TextToSpeechFacade |
Text-to-speech |
ToneGeneratorFacade |
DTMF tones |
WakeLockFacade |
Power management |
WebCamFacade |
Webcam streaming |
WifiFacade |
WiFi operations |