1434 lines
24 KiB
Markdown
1434 lines
24 KiB
Markdown
# A-Team Android ROM Builder — Technical Guide
|
||
|
||
## 1. Architecture at a Glance
|
||
|
||
A-Team Android ROM Builder is a Python/GTK application wrapped around a script-driven Android ROM workflow.
|
||
|
||
The central design is:
|
||
|
||
```text
|
||
GTK interface
|
||
|
|
||
v
|
||
Project state
|
||
|
|
||
+--> device configuration
|
||
|
|
||
+--> ROM configuration
|
||
|
|
||
+--> host configuration
|
||
|
|
||
+--> profile configuration
|
||
|
|
||
v
|
||
Environment generation
|
||
|
|
||
v
|
||
Bash scripts
|
||
|
|
||
+--> sync
|
||
+--> device setup
|
||
+--> GApps
|
||
+--> build
|
||
+--> clean
|
||
+--> updater
|
||
```
|
||
|
||
The GUI should be treated as the control plane. The scripts remain the execution plane.
|
||
|
||
That distinction is important when extending the application: a new ROM-specific operation normally belongs in the script/configuration layer rather than becoming a large block of shell logic inside a GTK callback.
|
||
|
||
---
|
||
|
||
## 2. Source Tree
|
||
|
||
The important top-level areas are:
|
||
|
||
```text
|
||
builder/
|
||
Python backend and application helpers
|
||
|
||
configs/
|
||
Device, ROM, host, setup, build-command, and upload configuration
|
||
|
||
profiles/
|
||
Saved project profiles
|
||
|
||
scripts/
|
||
Build and synchronization operations
|
||
|
||
gui.py
|
||
GTK application and tab construction
|
||
```
|
||
|
||
The project also contains application assets and supporting files used by the GUI.
|
||
|
||
---
|
||
|
||
## 3. `gui.py`
|
||
|
||
`gui.py` is the main GTK application.
|
||
|
||
It is responsible for:
|
||
|
||
- Creating the main window
|
||
- Creating the application tabs
|
||
- Creating controls
|
||
- Reading user selections
|
||
- Building the current project state
|
||
- Starting backend actions
|
||
- Starting scripts
|
||
- Displaying terminal output
|
||
- Displaying updater state
|
||
- Handling application-side UI tools
|
||
|
||
The application uses GTK 3 and VTE for the embedded terminal.
|
||
|
||
### UI constants
|
||
|
||
UI dimensions are intentionally centralized.
|
||
|
||
Current spacing controls include:
|
||
|
||
```text
|
||
BUILD_COMMANDS_TOP_BOTTOM_SPACING
|
||
BUILD_SETUP_TOP_SPACING
|
||
PROJECT_PROFILES_TOP_SPACING
|
||
SYNC_SETUP_TOP_SPACING
|
||
SPLASH_TOP_BOTTOM_SPACING
|
||
```
|
||
|
||
Current button-width controls include:
|
||
|
||
```text
|
||
SYNC_SETUP_BUTTON_WIDTH
|
||
SYNC_GAPPS_BUTTON_WIDTH
|
||
BUILD_ROM_BUTTON_WIDTH
|
||
LAUNCHER_BUTTON_WIDTH
|
||
CLEAN_BUTTON_WIDTH
|
||
```
|
||
|
||
Keep these constants centralized when modifying layout. Do not scatter repeated pixel values through widget construction unless there is a specific reason.
|
||
|
||
---
|
||
|
||
## 4. Configuration Parsing
|
||
|
||
The configuration system uses simple key/value files.
|
||
|
||
Example:
|
||
|
||
```text
|
||
DEVICE_CODENAME="milanf"
|
||
DEVICE_SOC="sm6375"
|
||
DEVICE_MANUFACTURER="Motorola"
|
||
```
|
||
|
||
Conceptually this becomes:
|
||
|
||
```python
|
||
{
|
||
"DEVICE_CODENAME": "milanf",
|
||
"DEVICE_SOC": "sm6375",
|
||
"DEVICE_MANUFACTURER": "Motorola"
|
||
}
|
||
```
|
||
|
||
Configuration parsing supports the project’s simple `KEY=VALUE` format and ignores comments and blank lines.
|
||
|
||
This intentionally avoids making device and ROM configuration dependent on Python code.
|
||
|
||
---
|
||
|
||
## 5. Device Discovery
|
||
|
||
Device discovery is configuration-driven.
|
||
|
||
The builder searches:
|
||
|
||
```text
|
||
configs/devices/
|
||
```
|
||
|
||
for device configuration files.
|
||
|
||
A new device therefore normally does not require a Python edit.
|
||
|
||
### Minimum device integration
|
||
|
||
Create:
|
||
|
||
```text
|
||
configs/devices/example.conf
|
||
```
|
||
|
||
Then provide the values required by the device scripts.
|
||
|
||
For example:
|
||
|
||
```text
|
||
DEVICE_CODENAME="example"
|
||
DEVICE_DISPLAY_CODENAME="Example"
|
||
DEVICE_DISPLAY_NAME="Example Android Device"
|
||
DEVICE_MANUFACTURER="Motorola"
|
||
DEVICE_MODEL_NUMBER="XT0000"
|
||
DEVICE_SYNC_SCRIPT="example-sync.sh"
|
||
```
|
||
|
||
The GUI can then discover the device from the configuration directory.
|
||
|
||
---
|
||
|
||
## 6. Device Sync Scripts
|
||
|
||
Device-specific scripts live under:
|
||
|
||
```text
|
||
scripts/devices_sync/
|
||
```
|
||
|
||
A device configuration points to its script:
|
||
|
||
```text
|
||
DEVICE_SYNC_SCRIPT="example-sync.sh"
|
||
```
|
||
|
||
The common synchronization workflow can then load the selected device configuration and execute the selected device-specific script.
|
||
|
||
### Recommended device addition procedure
|
||
|
||
1. Create the device `.conf`.
|
||
2. Add the device identity variables.
|
||
3. Add only device-specific variables that scripts actually require.
|
||
4. Create the device sync script.
|
||
5. Set `DEVICE_SYNC_SCRIPT`.
|
||
6. Test the script independently.
|
||
7. Start the GUI and confirm the device appears.
|
||
8. Run Sync & Setup Device Source.
|
||
|
||
Testing the shell script independently is useful because it separates Android source/setup failures from GTK failures.
|
||
|
||
---
|
||
|
||
## 7. ROM Configuration
|
||
|
||
ROM configuration can come from either:
|
||
|
||
```text
|
||
configs/rom.conf
|
||
```
|
||
|
||
or:
|
||
|
||
```text
|
||
<ROM_ROOT>/rom.conf
|
||
```
|
||
|
||
The ROM-local configuration is the preferred location when a ROM needs its own settings.
|
||
|
||
### Why two locations exist
|
||
|
||
The builder-wide file provides defaults.
|
||
|
||
The ROM-local file allows a ROM source tree to carry its own configuration.
|
||
|
||
For example:
|
||
|
||
```text
|
||
configs/rom.conf
|
||
```
|
||
|
||
could provide generic defaults while:
|
||
|
||
```text
|
||
/home/pizzag/Android/Roms/Lineage/23.2/rom.conf
|
||
```
|
||
|
||
contains values specific to that ROM tree.
|
||
|
||
### Case sensitivity
|
||
|
||
On Linux:
|
||
|
||
```text
|
||
rom.conf
|
||
Rom.conf
|
||
ROM.conf
|
||
```
|
||
|
||
are three different names.
|
||
|
||
The loader's expected filename is:
|
||
|
||
```text
|
||
rom.conf
|
||
```
|
||
|
||
---
|
||
|
||
## 8. ROM Configuration Variables
|
||
|
||
ROM configuration can contain build metadata and script variables.
|
||
|
||
Examples:
|
||
|
||
```text
|
||
ROM_BUILD_NAME="lineage"
|
||
ROM_TARGET_RELEASE="bp4a"
|
||
DEFAULT_ROM_BUILD_COMMAND="brunch $DEVICE_CODENAME"
|
||
ROM_DISPLAY_NAME="LineageOS"
|
||
ROM_VENDOR_NAME="lineage"
|
||
ROM_MANIFEST="https://github.com/LineageOS/android.git"
|
||
ROM_BRANCH_PREFIX="lineage-"
|
||
ROM_MAJOR_VERSION="23"
|
||
ROM_MINOR_VERSION="2"
|
||
```
|
||
|
||
The important principle is that the ROM configuration should contain values that describe the ROM rather than values that uniquely identify a single physical device.
|
||
|
||
Device-specific values belong in the device configuration.
|
||
|
||
---
|
||
|
||
## 9. Project State
|
||
|
||
The project state is the bridge between GUI selections and scripts.
|
||
|
||
Typical values include:
|
||
|
||
```text
|
||
DEVICE_NAME
|
||
ROM_NAME
|
||
ROM_BRANCH
|
||
ROM_PATH
|
||
ANDROID_VERSION
|
||
BUILD_VARIANT
|
||
BUILD_COMMAND
|
||
GAPPS_VARIANT
|
||
CLEAN_VARIANT
|
||
INSTALLER_VARIANT
|
||
BUILD_JOBS
|
||
USE_CCACHE
|
||
APN_VARIANT
|
||
```
|
||
|
||
Additional variables are merged from configuration sources.
|
||
|
||
The result is converted into an environment that can be consumed by Bash.
|
||
|
||
---
|
||
|
||
## 10. Environment Construction
|
||
|
||
The project environment combines GUI selections with configuration values.
|
||
|
||
A simplified model is:
|
||
|
||
```text
|
||
GUI/project values
|
||
|
|
||
v
|
||
device variables
|
||
|
|
||
v
|
||
ROM variables
|
||
|
|
||
v
|
||
A-Team setup variables
|
||
|
|
||
v
|
||
upload variables
|
||
|
|
||
v
|
||
variable expansion
|
||
```
|
||
|
||
This is what allows a configuration value such as:
|
||
|
||
```text
|
||
DEFAULT_ROM_BUILD_COMMAND="brunch $DEVICE_CODENAME"
|
||
```
|
||
|
||
to use the currently selected device without duplicating the device name in the ROM configuration.
|
||
|
||
When adding a new variable, decide whether it belongs to:
|
||
|
||
- project state
|
||
- device configuration
|
||
- ROM configuration
|
||
- A-Team setup
|
||
- upload configuration
|
||
|
||
before adding Python-specific handling.
|
||
|
||
---
|
||
|
||
## 11. ROM Path Interpretation
|
||
|
||
The selected ROM directory is used to derive ROM identity.
|
||
|
||
For example:
|
||
|
||
```text
|
||
/home/pizzag/Android/Roms/Lineage/23.2
|
||
```
|
||
|
||
can represent:
|
||
|
||
```text
|
||
ROM_NAME = Lineage
|
||
ROM_BRANCH = 23.2
|
||
ROM_PATH = /home/pizzag/Android/Roms/Lineage/23.2
|
||
```
|
||
|
||
The project then exports these values to the scripts.
|
||
|
||
This is why the expected ROM directory structure matters to the GUI.
|
||
|
||
---
|
||
|
||
## 12. Build Command System
|
||
|
||
The Build tab reads:
|
||
|
||
```text
|
||
configs/rom_build_commands.conf
|
||
```
|
||
|
||
Example:
|
||
|
||
```text
|
||
Default --> rom.conf
|
||
Lineage
|
||
Derpfest
|
||
```
|
||
|
||
Normal entries become selectable build commands.
|
||
|
||
The command implementation is deliberately separate from the GUI:
|
||
|
||
```text
|
||
scripts/build_options/rom_build_commands.sh
|
||
```
|
||
|
||
This allows the command selector to remain simple while the actual command-specific environment is handled in Bash.
|
||
|
||
---
|
||
|
||
## 13. `rom_build_commands()`
|
||
|
||
The build-command implementation is a Bash function:
|
||
|
||
```bash
|
||
rom_build_commands() {
|
||
...
|
||
}
|
||
```
|
||
|
||
It currently handles three paths.
|
||
|
||
### Lineage
|
||
|
||
```bash
|
||
if [[ $BUILD_COMMAND == "lineage" ]]; then
|
||
LUNCH_COMMAND="${ROM_BUILD_NAME}_${DEVICE_NAME}-${ROM_TARGET_RELEASE}-${BUILD_VARIANT}"
|
||
ROM_BUILD_COMMAND="brunch $DEVICE_CODENAME"
|
||
```
|
||
|
||
### Derpfest
|
||
|
||
```bash
|
||
elif [[ $BUILD_COMMAND == "derpfest" ]]; then
|
||
LUNCH_COMMAND="${ROM_BUILD_NAME}_${DEVICE_NAME}-${ROM_TARGET_RELEASE}-${BUILD_VARIANT}"
|
||
ROM_BUILD_COMMAND="m derp"
|
||
```
|
||
|
||
### Default
|
||
|
||
```bash
|
||
else
|
||
LUNCH_COMMAND="${ROM_BUILD_NAME}_${DEVICE_NAME}-${ROM_TARGET_RELEASE}-${BUILD_VARIANT}"
|
||
ROM_BUILD_COMMAND="$DEFAULT_ROM_BUILD_COMMAND"
|
||
```
|
||
|
||
Each branch exports:
|
||
|
||
```text
|
||
LUNCH_COMMAND
|
||
ROM_BUILD_COMMAND
|
||
```
|
||
|
||
### Why the function is sourced
|
||
|
||
`build.sh` uses:
|
||
|
||
```bash
|
||
source "$BUILD_OPTIONS_DIR/rom_build_commands.sh"
|
||
rom_build_commands
|
||
```
|
||
|
||
It is important that the file is sourced rather than executed with a separate `bash` process.
|
||
|
||
If the function ran in a child shell, exported variables would not remain available to the parent build script.
|
||
|
||
---
|
||
|
||
## 14. Build Execution
|
||
|
||
The build entry point is:
|
||
|
||
```text
|
||
scripts/build.sh
|
||
```
|
||
|
||
The script receives the project environment and performs the build preparation.
|
||
|
||
The command-selection flow is:
|
||
|
||
```text
|
||
GUI selection
|
||
|
|
||
v
|
||
BUILD_COMMAND
|
||
|
|
||
v
|
||
rom_build_commands()
|
||
|
|
||
+--> LUNCH_COMMAND
|
||
|
|
||
+--> ROM_BUILD_COMMAND
|
||
|
|
||
v
|
||
build execution
|
||
```
|
||
|
||
The current implementation uses the resulting command strings for the ROM build.
|
||
|
||
When a command is stored as a string containing shell syntax or multiple arguments, the build script must execute it in a way consistent with how the command is defined.
|
||
|
||
---
|
||
|
||
## 15. Build Options
|
||
|
||
The GUI exposes project-level build options.
|
||
|
||
### Android version
|
||
|
||
The selected Android version is exported as:
|
||
|
||
```text
|
||
ANDROID_VERSION
|
||
```
|
||
|
||
### Build variant
|
||
|
||
The project supports the Android build variants exposed by the current GUI.
|
||
|
||
The selected value becomes:
|
||
|
||
```text
|
||
BUILD_VARIANT
|
||
```
|
||
|
||
### GApps
|
||
|
||
The selected GApps mode becomes:
|
||
|
||
```text
|
||
GAPPS_VARIANT
|
||
```
|
||
|
||
### Clean
|
||
|
||
The clean selection becomes:
|
||
|
||
```text
|
||
CLEAN_VARIANT
|
||
```
|
||
|
||
### Installer
|
||
|
||
The installer selection becomes:
|
||
|
||
```text
|
||
INSTALLER_VARIANT
|
||
```
|
||
|
||
### Build jobs
|
||
|
||
The selected job count becomes:
|
||
|
||
```text
|
||
BUILD_JOBS
|
||
```
|
||
|
||
### Ccache
|
||
|
||
The checkbox controls:
|
||
|
||
```text
|
||
USE_CCACHE
|
||
```
|
||
|
||
### Custom APN
|
||
|
||
The Custom APN option controls the APN-related project value consumed by the build scripts.
|
||
|
||
---
|
||
|
||
## 16. Sync Workflow
|
||
|
||
The common synchronization entry point is:
|
||
|
||
```text
|
||
scripts/sync.sh
|
||
```
|
||
|
||
Its role is to coordinate common setup and then dispatch to the selected device workflow.
|
||
|
||
The architecture is:
|
||
|
||
```text
|
||
sync.sh
|
||
|
|
||
+--> load configuration
|
||
|
|
||
+--> establish A-Team setup
|
||
|
|
||
+--> select device script
|
||
|
|
||
+--> execute device sync
|
||
```
|
||
|
||
Device-specific behavior remains in:
|
||
|
||
```text
|
||
scripts/devices_sync/
|
||
```
|
||
|
||
This prevents the common sync script from becoming a large device-specific conditional tree.
|
||
|
||
---
|
||
|
||
## 17. A-Team Setup Marker
|
||
|
||
The project uses a setup marker under the ROM tree to identify whether the A-Team setup process has already been performed.
|
||
|
||
The marker is:
|
||
|
||
```text
|
||
device/A-Team/A-Team-Setup.check
|
||
```
|
||
|
||
The purpose is to prevent the common setup work from being repeated unnecessarily.
|
||
|
||
If the setup requirements change, the marker/versioning logic should be reviewed so existing ROM trees can be migrated safely.
|
||
|
||
---
|
||
|
||
## 18. MindTheGapps Synchronization
|
||
|
||
GApps synchronization is handled by:
|
||
|
||
```text
|
||
scripts/gapps_sync.sh
|
||
```
|
||
|
||
The script uses the Android version to determine the appropriate MindTheGapps source.
|
||
|
||
The source is synchronized into the ROM tree at the location expected by the current build system.
|
||
|
||
This operation is separate from the core ROM build so it can be repeated without rebuilding the entire ROM.
|
||
|
||
---
|
||
|
||
## 19. Project Profiles
|
||
|
||
Profiles are stored under:
|
||
|
||
```text
|
||
profiles/
|
||
```
|
||
|
||
A profile represents a reusable set of project selections.
|
||
|
||
Examples of profile-level information include:
|
||
|
||
```text
|
||
device
|
||
ROM path
|
||
Android version
|
||
build variant
|
||
build command
|
||
GApps variant
|
||
clean variant
|
||
installer variant
|
||
build jobs
|
||
ccache
|
||
APN selection
|
||
host
|
||
```
|
||
|
||
Profiles should not be used as a replacement for device or ROM configuration files.
|
||
|
||
A profile says:
|
||
|
||
> "Build this project this way."
|
||
|
||
A device configuration says:
|
||
|
||
> "This is how this device is defined."
|
||
|
||
A ROM configuration says:
|
||
|
||
> "This is how this ROM is defined."
|
||
|
||
Keeping those responsibilities separate makes the project easier to maintain.
|
||
|
||
---
|
||
|
||
## 20. Build Hosts
|
||
|
||
Host configuration is stored in:
|
||
|
||
```text
|
||
configs/hosts.conf
|
||
```
|
||
|
||
The builder supports local and SSH-based hosts.
|
||
|
||
A remote host needs:
|
||
|
||
- SSH access
|
||
- Android build dependencies
|
||
- ROM source
|
||
- required device/vendor/kernel source
|
||
- Git and other source-management tools
|
||
- any ROM-specific build dependencies
|
||
|
||
The host configuration tells the application how to reach the machine; it does not replace the machine's Android build environment.
|
||
|
||
---
|
||
|
||
## 21. Embedded Terminal
|
||
|
||
The terminal uses VTE and provides a real interactive shell inside the application.
|
||
|
||
The terminal is intentionally not treated as a static output window.
|
||
|
||
It supports shell input and now provides desktop clipboard integration for terminal text.
|
||
|
||
### Copy
|
||
|
||
Selected terminal text can be copied to the system clipboard.
|
||
|
||
The terminal copy action should not replace normal:
|
||
|
||
```text
|
||
Ctrl+C
|
||
```
|
||
|
||
terminal behavior, because Ctrl+C is commonly used to interrupt a running process.
|
||
|
||
### Paste
|
||
|
||
Clipboard contents can be inserted into the terminal.
|
||
|
||
### Design consideration
|
||
|
||
Terminal keyboard shortcuts must be implemented carefully because shortcuts such as Ctrl+C have established Unix terminal semantics.
|
||
|
||
---
|
||
|
||
## 22. Resource Monitor
|
||
|
||
The Resource Monitor provides live system information through:
|
||
|
||
```text
|
||
btop
|
||
```
|
||
|
||
with:
|
||
|
||
```text
|
||
bpytop
|
||
```
|
||
|
||
as a fallback where supported by the current implementation.
|
||
|
||
It is particularly useful during Android builds because compilation can consume large amounts of:
|
||
|
||
- CPU
|
||
- RAM
|
||
- storage I/O
|
||
- swap
|
||
- filesystem capacity
|
||
|
||
---
|
||
|
||
## 23. Tools
|
||
|
||
The Tools area contains application-side utilities.
|
||
|
||
### Splash selection
|
||
|
||
The splash manager handles selection of available splash assets.
|
||
|
||
### Launcher icons
|
||
|
||
The icon manager handles launcher icon selection.
|
||
|
||
### Desktop launcher
|
||
|
||
The launcher utility creates a desktop entry for the builder.
|
||
|
||
### Clean ROM
|
||
|
||
The clean operation invokes the appropriate backend/script workflow rather than embedding a large cleanup implementation in the GUI.
|
||
|
||
---
|
||
|
||
## 24. Updater Architecture
|
||
|
||
The updater has three distinct responsibilities:
|
||
|
||
```text
|
||
Python updater logic
|
||
|
|
||
+--> update discovery
|
||
+--> download/extraction
|
||
|
|
||
GTK updater UI
|
||
|
|
||
+--> progress bar
|
||
+--> status text
|
||
+--> update dialog
|
||
|
|
||
scripts/updater.sh
|
||
|
|
||
+--> actual staged update operations
|
||
```
|
||
|
||
This separation matters because the shell script reports what is happening, while the GUI decides how those reports are presented.
|
||
|
||
---
|
||
|
||
## 25. Updater Progress Protocol
|
||
|
||
The shell updater communicates progress using:
|
||
|
||
```text
|
||
::PROGRESS::<current>::<total>
|
||
```
|
||
|
||
For example:
|
||
|
||
```text
|
||
::PROGRESS::3::5
|
||
```
|
||
|
||
represents:
|
||
|
||
```text
|
||
3 / 5
|
||
```
|
||
|
||
or:
|
||
|
||
```text
|
||
60%
|
||
```
|
||
|
||
Status messages use:
|
||
|
||
```text
|
||
::STATUS::<message>
|
||
```
|
||
|
||
Example:
|
||
|
||
```text
|
||
::STATUS::Backing Up Current Installation ...
|
||
```
|
||
|
||
The GUI listens for these markers and updates the updater interface.
|
||
|
||
### Adding an updater stage
|
||
|
||
If another stage is required:
|
||
|
||
1. Increase `TOTAL_STEPS`.
|
||
2. Add a `::PROGRESS::N::TOTAL` message.
|
||
3. Add the corresponding `::STATUS::...` message.
|
||
4. Keep the numbering sequential.
|
||
5. Test both the script and GUI interpretation.
|
||
|
||
Do not change the marker syntax unless the Python parser is changed at the same time.
|
||
|
||
---
|
||
|
||
## 26. Updater Status Appearance
|
||
|
||
Updater status messages are intentionally displayed in:
|
||
|
||
```text
|
||
cyan
|
||
bold
|
||
```
|
||
|
||
The status text is separate from the progress calculation.
|
||
|
||
Therefore:
|
||
|
||
```text
|
||
status appearance
|
||
```
|
||
|
||
can be changed without changing:
|
||
|
||
```text
|
||
progress percentage
|
||
```
|
||
|
||
and vice versa.
|
||
|
||
The progress calculation is based on:
|
||
|
||
```text
|
||
current / total
|
||
```
|
||
|
||
while the status label is simply the human-readable description associated with that stage.
|
||
|
||
---
|
||
|
||
## 27. Update JSON and Changelog
|
||
|
||
The update JSON is loaded as a complete object.
|
||
|
||
The update popup uses the available version information and the optional:
|
||
|
||
```json
|
||
"changelog": "..."
|
||
```
|
||
|
||
field.
|
||
|
||
For example:
|
||
|
||
```json
|
||
{
|
||
"version": 102,
|
||
"display": "1.02",
|
||
"file": "A-Team-Android_ROM_Builder-v1.02.7z",
|
||
"changelog": "Improved terminal clipboard support."
|
||
}
|
||
```
|
||
|
||
The popup can present:
|
||
|
||
```text
|
||
Installed Version : 1.01
|
||
Available Version : 1.02
|
||
|
||
Changelog:
|
||
Improved terminal clipboard support.
|
||
```
|
||
|
||
If the field is absent, the application uses its fallback text rather than failing the update dialog.
|
||
|
||
---
|
||
|
||
## 28. Adding a Device — Complete Example
|
||
|
||
Suppose a new device is called:
|
||
|
||
```text
|
||
example
|
||
```
|
||
|
||
### Device configuration
|
||
|
||
Create:
|
||
|
||
```text
|
||
configs/devices/example.conf
|
||
```
|
||
|
||
Example:
|
||
|
||
```text
|
||
DEVICE_CODENAME="example"
|
||
DEVICE_DISPLAY_CODENAME="Example"
|
||
DEVICE_DISPLAY_NAME="Example Phone"
|
||
DEVICE_MANUFACTURER="Motorola"
|
||
DEVICE_MODEL_NUMBER="XT0000"
|
||
DEVICE_SYNC_SCRIPT="example-sync.sh"
|
||
```
|
||
|
||
### Device sync script
|
||
|
||
Create:
|
||
|
||
```text
|
||
scripts/devices_sync/example-sync.sh
|
||
```
|
||
|
||
Make it executable:
|
||
|
||
```bash
|
||
chmod +x scripts/devices_sync/example-sync.sh
|
||
```
|
||
|
||
### Test it
|
||
|
||
Run it manually with the required environment before involving the GUI.
|
||
|
||
### Test discovery
|
||
|
||
Start the GUI and verify that:
|
||
|
||
```text
|
||
Example Phone
|
||
```
|
||
|
||
appears in the device selector.
|
||
|
||
### Test sync
|
||
|
||
Select the device and run:
|
||
|
||
```text
|
||
Sync & Setup Device Source
|
||
```
|
||
|
||
This isolates the device integration into configuration plus one device-specific script.
|
||
|
||
---
|
||
|
||
## 29. Adding a ROM
|
||
|
||
A new ROM normally needs:
|
||
|
||
1. A valid ROM source tree.
|
||
2. A recognizable ROM path.
|
||
3. A ROM configuration.
|
||
4. A compatible build command.
|
||
5. Any required synchronization logic.
|
||
|
||
If the ROM has unique settings, put them in:
|
||
|
||
```text
|
||
<ROM_ROOT>/rom.conf
|
||
```
|
||
|
||
rather than modifying the global:
|
||
|
||
```text
|
||
configs/rom.conf
|
||
```
|
||
|
||
If it needs a unique build command, add the command to:
|
||
|
||
```text
|
||
configs/rom_build_commands.conf
|
||
```
|
||
|
||
and implement the command behavior in:
|
||
|
||
```text
|
||
scripts/build_options/rom_build_commands.sh
|
||
```
|
||
|
||
---
|
||
|
||
## 30. Adding a Build Command
|
||
|
||
There are two parts.
|
||
|
||
### Part 1 — GUI selection
|
||
|
||
Add the command name to:
|
||
|
||
```text
|
||
configs/rom_build_commands.conf
|
||
```
|
||
|
||
For example:
|
||
|
||
```text
|
||
Aosp
|
||
```
|
||
|
||
### Part 2 — command behavior
|
||
|
||
Add a branch to:
|
||
|
||
```text
|
||
rom_build_commands()
|
||
```
|
||
|
||
For example:
|
||
|
||
```bash
|
||
elif [[ $BUILD_COMMAND == "aosp" ]]; then
|
||
LUNCH_COMMAND="${ROM_BUILD_NAME}_${DEVICE_NAME}-${ROM_TARGET_RELEASE}-${BUILD_VARIANT}"
|
||
ROM_BUILD_COMMAND="m"
|
||
export LUNCH_COMMAND
|
||
export ROM_BUILD_COMMAND
|
||
```
|
||
|
||
Then run:
|
||
|
||
```bash
|
||
bash -n scripts/build_options/rom_build_commands.sh
|
||
```
|
||
|
||
before testing the GUI.
|
||
|
||
---
|
||
|
||
## 31. Adding a Configuration Variable
|
||
|
||
Before adding a new variable, identify its scope.
|
||
|
||
### Device scope
|
||
|
||
```text
|
||
configs/devices/<device>.conf
|
||
```
|
||
|
||
Use for:
|
||
|
||
```text
|
||
SOC
|
||
codename
|
||
model
|
||
device-specific paths
|
||
device-specific flags
|
||
```
|
||
|
||
### ROM scope
|
||
|
||
```text
|
||
rom.conf
|
||
```
|
||
|
||
Use for:
|
||
|
||
```text
|
||
ROM name
|
||
ROM build metadata
|
||
ROM default command
|
||
ROM manifest
|
||
ROM release metadata
|
||
```
|
||
|
||
### Application-wide setup
|
||
|
||
```text
|
||
configs/a_team_setup.conf
|
||
```
|
||
|
||
Use for values shared across projects.
|
||
|
||
### Upload services
|
||
|
||
```text
|
||
configs/upload_services.conf
|
||
```
|
||
|
||
Use for upload-service configuration.
|
||
|
||
Keeping variable scope correct prevents device-specific details from leaking into ROM-wide configuration.
|
||
|
||
---
|
||
|
||
## 32. Debugging Strategy
|
||
|
||
When something fails, isolate the layer.
|
||
|
||
### GUI problem
|
||
|
||
Check:
|
||
|
||
```text
|
||
gui.py
|
||
builder/*.py
|
||
```
|
||
|
||
### Configuration problem
|
||
|
||
Check:
|
||
|
||
```text
|
||
configs/
|
||
profiles/
|
||
```
|
||
|
||
### Sync problem
|
||
|
||
Run:
|
||
|
||
```text
|
||
scripts/sync.sh
|
||
```
|
||
|
||
directly.
|
||
|
||
### Device problem
|
||
|
||
Run the device-specific script directly.
|
||
|
||
### Build problem
|
||
|
||
Run:
|
||
|
||
```text
|
||
scripts/build.sh
|
||
```
|
||
|
||
directly with the required environment.
|
||
|
||
### Updater problem
|
||
|
||
Run:
|
||
|
||
```text
|
||
scripts/updater.sh
|
||
```
|
||
|
||
directly and inspect:
|
||
|
||
```text
|
||
::PROGRESS::
|
||
::STATUS::
|
||
```
|
||
|
||
output.
|
||
|
||
This approach avoids changing GUI code to solve a shell or Android-source problem.
|
||
|
||
---
|
||
|
||
## 33. Bash Validation
|
||
|
||
Before committing a shell change:
|
||
|
||
```bash
|
||
bash -n scripts/build.sh
|
||
bash -n scripts/sync.sh
|
||
bash -n scripts/gapps_sync.sh
|
||
bash -n scripts/updater.sh
|
||
```
|
||
|
||
For the command-selection function:
|
||
|
||
```bash
|
||
bash -n scripts/build_options/rom_build_commands.sh
|
||
```
|
||
|
||
Syntax validation does not prove that an Android build will succeed, but it catches malformed shell syntax before a full build.
|
||
|
||
---
|
||
|
||
## 34. Python Validation
|
||
|
||
For Python changes:
|
||
|
||
```bash
|
||
python3 -m py_compile gui.py
|
||
```
|
||
|
||
and for backend modules:
|
||
|
||
```bash
|
||
python3 -m py_compile builder/*.py
|
||
```
|
||
|
||
For GTK changes, syntax validation is not enough.
|
||
|
||
The affected UI path should also be exercised in an environment containing:
|
||
|
||
```text
|
||
gi
|
||
Gtk 3
|
||
VTE
|
||
```
|
||
|
||
because GTK errors commonly occur during widget creation or signal execution rather than Python parsing.
|
||
|
||
---
|
||
|
||
## 35. Preserving Executable Permissions
|
||
|
||
The application contains executable shell scripts.
|
||
|
||
Important files include:
|
||
|
||
```text
|
||
scripts/*.sh
|
||
scripts/build_options/*.sh
|
||
scripts/devices_sync/*.sh
|
||
```
|
||
|
||
The updater is one example where executable permissions matter because the Python updater launches:
|
||
|
||
```text
|
||
scripts/updater.sh
|
||
```
|
||
|
||
directly.
|
||
|
||
When packaging a release, preserve executable mode, normally:
|
||
|
||
```text
|
||
0755
|
||
```
|
||
|
||
for shell scripts and the executable application entry point where applicable.
|
||
|
||
A ZIP process that strips Unix permissions can cause:
|
||
|
||
```text
|
||
PermissionError: [Errno 13] Permission denied
|
||
```
|
||
|
||
even when the script contents themselves are correct.
|
||
|
||
---
|
||
|
||
## 36. UI Extension Pattern
|
||
|
||
For a new button:
|
||
|
||
1. Add a width constant if its width should be configurable.
|
||
2. Create the GTK button.
|
||
3. Apply the shared sizing/alignment helper.
|
||
4. Connect its callback.
|
||
5. Put the actual operation in an appropriate backend or script.
|
||
|
||
For example:
|
||
|
||
```python
|
||
MY_BUTTON_WIDTH = 140
|
||
```
|
||
|
||
then:
|
||
|
||
```python
|
||
set_button_width(
|
||
my_button,
|
||
MY_BUTTON_WIDTH
|
||
)
|
||
```
|
||
|
||
This keeps layout changes localized.
|
||
|
||
---
|
||
|
||
## 37. UI Layout Maintenance
|
||
|
||
When adjusting spacing:
|
||
|
||
- Change the corresponding named constant.
|
||
- Avoid replacing unrelated margins.
|
||
- Keep the existing alignment model.
|
||
- Do not duplicate spacing constants for the same visual relationship.
|
||
- Verify the neighboring controls after a change.
|
||
|
||
The current UI intentionally exposes independent spacing values for sections that need independent tuning.
|
||
|
||
---
|
||
|
||
## 38. Recommended Development Workflow
|
||
|
||
For a new feature:
|
||
|
||
### Step 1 — Identify the layer
|
||
|
||
Decide whether the feature belongs in:
|
||
|
||
```text
|
||
GUI
|
||
backend
|
||
config
|
||
script
|
||
```
|
||
|
||
### Step 2 — Find the existing path
|
||
|
||
Reuse the existing action/config/script architecture where possible.
|
||
|
||
### Step 3 — Make the smallest change
|
||
|
||
Avoid changing unrelated layout or configuration code.
|
||
|
||
### Step 4 — Validate syntax
|
||
|
||
Run Python or Bash syntax checks.
|
||
|
||
### Step 5 — Exercise the affected operation
|
||
|
||
Do not stop at syntax validation.
|
||
|
||
### Step 6 — Verify packaging
|
||
|
||
Ensure scripts retain executable permissions.
|
||
|
||
### Step 7 — Update documentation
|
||
|
||
Update `README.md` for user-visible functionality and `README-TECHNICAL.md` for implementation details.
|
||
|
||
---
|
||
|
||
## 39. Documentation Boundary
|
||
|
||
`README.md` should answer:
|
||
|
||
> What does the application do, how do I run it, and how do I configure it?
|
||
|
||
`README-TECHNICAL.md` should answer:
|
||
|
||
> How does it work, where is the code, how do the components communicate, and how do I extend or debug it?
|
||
|
||
Avoid duplicating every implementation detail in the normal README.
|
||
|
||
The technical document should be detailed where implementation knowledge matters, but should remain organized around the application's actual architecture and workflows.
|
||
|
||
---
|
||
|
||
## 40. Current Extension Points
|
||
|
||
The cleanest existing extension points are:
|
||
|
||
```text
|
||
configs/devices/
|
||
Add devices
|
||
|
||
configs/rom.conf
|
||
Add ROM defaults
|
||
|
||
<ROM_ROOT>/rom.conf
|
||
Add ROM-local configuration
|
||
|
||
configs/rom_build_commands.conf
|
||
Add build command choices
|
||
|
||
scripts/devices_sync/
|
||
Add device-specific sync logic
|
||
|
||
scripts/build_options/
|
||
Add build-option behavior
|
||
|
||
scripts/
|
||
Add reusable workflow operations
|
||
|
||
builder/
|
||
Add reusable Python-side functionality
|
||
|
||
gui.py
|
||
Add/modify user interface
|
||
```
|
||
|
||
When possible, use these extension points instead of introducing special-case logic into unrelated components.
|