Spectrum 2.4GHz is an open-source Android application, and contributions of all kinds are welcome — whether you are fixing a bug, improving the scan visualisation, or adding support for a new security protocol. This guide explains how to set up a development environment, the conventions the codebase follows, and the patterns you should use when extending specific parts of the app.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/anfegomezver/spectrum24ghz/llms.txt
Use this file to discover all available pages before exploring further.
Contributions, bug reports, and feature requests are welcome via GitHub Issues at github.com/anfegomezver/spectrum24ghz. If you are reporting a bug, include your Android version, device model, and a description of the observed vs. expected behaviour.
Getting Started
Create a feature branch
Always work on a dedicated branch — never commit directly to Use descriptive branch names such as
main:fix/scan-timeout-edge-case or feature/channel-14-support.Make your changes
Open the project in Android Studio, implement your changes, and verify that the app builds and runs correctly on a physical device or emulator. See the build requirements below.
Build Requirements
| Requirement | Details |
|---|---|
| IDE | Android Studio (latest stable) |
| Android SDK | API 34 (Android 14) installed via SDK Manager |
| Java version | Java 8 (JavaVersion.VERSION_1_8) |
| Min device | Android 6.0 (API 23) physical or virtual device |
Language: Java, Not Kotlin
The entire codebase is written in Java. Do not introduce Kotlin source files. Maintaining a single language throughout avoids mixed-language build complexity and keeps the contribution barrier low. If you migrate any class to Kotlin you will need to configure the Kotlin Gradle plugin — that change is outside the scope of a typical feature contribution.Code Style Guidance
Single-Activity architecture
The app uses oneActivity (MainActivity) with no Fragments. Do not add Fragments unless there is a compelling reason that cannot be addressed by adding a new custom view or updating selectTab(int). The simplicity of the current structure is intentional: it keeps all scan state in one place and avoids Fragment back-stack complexity.
Scan logic stays in MainActivity
All Wi-Fi scanning logic — permission checking, theBroadcastReceiver, the 30-second cooldown, the 12-second timeout, and the call to wifiManager.startScan() — lives in MainActivity. Do not move this logic into a Repository, ViewModel, or background Service without discussing the change in an Issue first, as it touches Android permission and lifecycle contracts that are currently handled at the Activity level.
Custom views are self-contained Canvas implementations
TimeGraphView and StatisticsGraphView both extend android.view.View directly and render everything in onDraw(Canvas). Keep this pattern: custom views should accept data via a single public update*() method, store it internally, and call invalidate(). Do not pass Context-dependent resources (colour lookups, dimension lookups) through the update method — resolve them in init() or onAttachedToWindow() instead.
Model classes use constructor-only initialisation
ScannedNetwork is fully immutable — all seven fields are final and set through the constructor:
ScannedNetwork, add it to the constructor signature and update every call site in MainActivity.populateNetworks(). Do not add setters.
WifiChannel follows the same rule with one intentional exception: setExpanded(boolean) is a mutable UI-state field used by adapters to track expand/collapse state. New fields that represent channel metadata (not transient UI state) should be added via the constructor.
RecyclerView adapters use the ViewHolder + View Binding pattern
BothNetworkAdapter and ChannelListAdapter follow this pattern:
itemView.findViewById() — always use the generated View Binding class for the item layout.
Adding a New Tab View
If you want to add a fifth visualisation tab, follow these steps:- Add a tab button to
activity_main.xmlfollowing the same structure as the existingtabList,tabChannels,tabTime, andtabStatsviews. - Register a click listener in
MainActivity.onCreate(): - Handle the new index inside
selectTab(int tabIndex): set visibility for the new view and update the selected/unselected text colours. - Create a new custom View class (e.g.,
MyCustomView.java) that extendsandroid.view.Viewand implementsonDraw(Canvas)if the tab requires canvas rendering. For simple list-based tabs, aRecyclerViewwith a new adapter is sufficient.
Extending Security Protocol Support
ThegetSecurityLabel() method in ScannedNetwork parses the capabilities string returned by WifiManager.getScanResults() to derive a human-readable label:
contains() branch before the generic WPA3 check, since keyword matching is evaluated top-to-bottom. After updating getSecurityLabel(), verify that the new label appears correctly in the Statistics tab’s Security Types chart and in the network detail dialog.
Running Tests
The project includes two test classes that should continue to pass after any change:ExampleUnitTest— a JVM unit test (no device required). Run it with:ExampleInstrumentedTest— an instrumented test usingandroidx.test.ext.junitthat runs on a real device or emulator. Run it with: