Skip to content

Commit 903780a

Browse files
authored
Merge branch 'main' into lang
2 parents e6bd8aa + 7be50d0 commit 903780a

26 files changed

Lines changed: 579 additions & 306 deletions

.github/workflows/android-ci.yml

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ on:
44
push:
55
paths-ignore:
66
- '**/*.md'
7-
- '.github/workflows/android-emulator-test.yml'
87
- '.github/workflows/codeql-analysis.yml'
98
- '.github/workflows/close-empty-xml.yml'
109
- '.github/workflows/stale.yml'
1110
- '.github/workflows/compare-src.yml'
1211
pull_request:
1312
paths-ignore:
1413
- '**/*.md'
15-
- '.github/workflows/android-emulator-test.yml'
1614
- '.github/workflows/codeql-analysis.yml'
1715
- '.github/workflows/close-empty-xml.yml'
1816
- '.github/workflows/stale.yml'
@@ -91,3 +89,54 @@ jobs:
9189
with:
9290
name: artifact-apk
9391
path: app/build/outputs/apk/debug
92+
93+
emulator-test:
94+
runs-on: ubuntu-latest
95+
needs: [build-apk]
96+
strategy:
97+
fail-fast: false
98+
matrix:
99+
api-level: [35]
100+
steps:
101+
- uses: actions/checkout@v4
102+
- uses: ./.github/actions/common-setup
103+
- name: Enable KVM
104+
run: |
105+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
106+
sudo udevadm control --reload-rules
107+
sudo udevadm trigger --name-match=kvm
108+
- name: Gradle cache
109+
uses: gradle/actions/setup-gradle@v4
110+
- name: AVD cache
111+
uses: actions/cache@v4
112+
id: avd-cache
113+
with:
114+
path: |
115+
~/.android/avd/*
116+
~/.android/adb*
117+
key: avd-${{ matrix.api-level }}
118+
- name: Create AVD and generate snapshot for caching
119+
if: steps.avd-cache.outputs.cache-hit != 'true'
120+
uses: ./.github/actions/emulator-step
121+
with:
122+
api-level: ${{ matrix.api-level }}
123+
script: echo "Generated AVD snapshot for caching."
124+
- name: Build app and test APKs
125+
run: ./gradlew assembleDebug assembleDebugAndroidTest
126+
- name: Run instrumented tests
127+
uses: ./.github/actions/emulator-step
128+
with:
129+
api-level: ${{ matrix.api-level }}
130+
script: ./gradlew connectedDebugAndroidTest -x assembleDebug -x assembleDebugAndroidTest
131+
- name: Upload test results
132+
uses: actions/upload-artifact@v4
133+
if: always()
134+
with:
135+
name: emulator-test-results-${{ matrix.api-level }}
136+
path: app/build/reports/androidTests
137+
- name: Publish test results
138+
uses: mikepenz/action-junit-report@v5
139+
if: always()
140+
with:
141+
report_paths: 'app/build/outputs/androidTest-results/connected/**/*.xml'
142+

.github/workflows/android-emulator-test.yml

Lines changed: 0 additions & 60 deletions
This file was deleted.

.github/workflows/close-empty-xml.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,9 @@ jobs:
3030
3131
echo "Files variable content: [${FILES}]"
3232
33-
# If no xml files changed, close the PR with a comment and exit cleanly.
33+
# If no xml files changed, do nothing and exit cleanly.
3434
if [ -z "$FILES" ]; then
35-
echo "No XML files changed. Closing PR."
36-
gh pr close ${{ github.event.pull_request.number }} --comment "Closed: No meaningful translation content in XML files." || true
35+
echo "No XML files changed. Skipping translation check."
3736
exit 0
3837
fi
3938

.github/workflows/codeql-analysis.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ on:
33
push:
44
paths-ignore:
55
- '**/*.md'
6-
- '.github/workflows/android-emulator-test.yml'
76
- '.github/workflows/close-empty-xml.yml'
87
- '.github/workflows/stale.yml'
98
- '.github/workflows/compare-src.yml'
109
pull_request:
1110
paths-ignore:
1211
- '**/*.md'
13-
- '.github/workflows/android-emulator-test.yml'
1412
- '.github/workflows/close-empty-xml.yml'
1513
- '.github/workflows/stale.yml'
1614
- '.github/workflows/compare-src.yml'

AGENTS.md

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ WiFiAnalyzer is an Android application for analyzing WiFi networks. It helps use
2525
## Project Structure
2626

2727
```
28-
app/src/main/kotlin/ # Main source code
29-
app/src/test/kotlin/ # Unit tests
28+
app/src/main/kotlin/ # Main application source code
29+
app/src/test/kotlin/ # Unit tests
3030
app/src/androidTest/kotlin/ # Android instrumentation tests
3131
```
3232

@@ -75,30 +75,44 @@ All new features and bug fixes MUST include unit tests.
7575

7676
### Test File Naming
7777

78-
Test files follow the pattern `[ClassName]Test.kt`
78+
Test files use several patterns, including but not limited to:
79+
- `[ClassName]Test.kt`
80+
- `[ClassName]InstrumentedTest.kt`
81+
- `[ClassName]IntegrationTest.kt`
82+
- `[ClassName]ParameterizedTest.kt`
83+
- `[ClassName]TestUtil.kt`
84+
85+
Use the pattern that best describes the test's purpose. Document any deviations from these patterns in your code or pull request to maintain clarity.
7986

8087
### Test Structure (AAA Pattern)
8188

8289
```kotlin
8390
@Test
84-
fun testMethodName() {
91+
fun shouldReturnCorrectVersionNumber() {
8592
// Arrange: Set up test data and mocks
86-
8793
// Act: Execute the code being tested
88-
8994
// Assert: Verify the results
9095
}
9196
```
9297

9398
### Testing Patterns Used
9499

95-
**Mockito with Kotlin extensions:**
100+
// Example imports for test files:
96101
```kotlin
97102
import org.mockito.kotlin.mock
98103
import org.mockito.kotlin.verify
99104
import org.mockito.kotlin.whenever
100105
```
101106

107+
// Example imports for assertions:
108+
```kotlin
109+
import org.assertj.core.api.Assertions.assertThat
110+
111+
assertThat(actual).isEqualTo(expected)
112+
assertThat(actual).isTrue
113+
assertThat(actual).isNotNull()
114+
```
115+
102116
**Test teardown pattern:**
103117
```kotlin
104118
@After
@@ -107,13 +121,34 @@ fun tearDown() {
107121
}
108122
```
109123

110-
**Robolectric for Android components:**
124+
**Robolectric for Android components (use RobolectricUtil helper):**
111125
```kotlin
112-
val activity = Robolectric
113-
.buildActivity(MainActivity::class.java)
114-
.create()
115-
.resume()
116-
.get()
126+
import com.vrem.wifianalyzer.RobolectricUtil
127+
128+
private val mainActivity = RobolectricUtil.INSTANCE.activity
129+
130+
// For fragments:
131+
RobolectricUtil.INSTANCE.startFragment(fragment)
132+
```
133+
134+
## Android Instrumentation Test Conventions
135+
136+
- Instrumentation test files are located in `app/src/androidTest/kotlin/`.
137+
- File names typically follow the pattern `[ClassName]InstrumentedTest.kt`.
138+
- Use the `@RunWith(AndroidJUnit4::class)` annotation for instrumentation tests.
139+
- Access UI components using Espresso or Robolectric as appropriate.
140+
- Example instrumentation test structure:
141+
142+
```kotlin
143+
@RunWith(AndroidJUnit4::class)
144+
class MainActivityInstrumentedTest {
145+
@Test
146+
fun shouldDisplayMainScreen() {
147+
// Arrange: Launch activity
148+
// Act: Interact with UI
149+
// Assert: Verify UI state
150+
}
151+
}
117152
```
118153

119154
## Build Commands

USER_MANUAL.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- [Basic Navigation](#basic-navigation)
66
- [Basic Operations](#basic-operations)
7+
- [Filtering](#filtering)
78
- [Settings and Customization](#settings-and-customization)
89
- [Advanced Settings](#advanced-settings)
910
- [Interpreting Wi-Fi Data](#interpreting-wi-fi-data)
@@ -35,15 +36,32 @@
3536
* **Channel Graph:** Switch to the channel graph to see how access points are distributed across different Wi-Fi channels.
3637
* **Time Graph:** Select an access point and switch to the time graph to monitor its signal strength over time.
3738
* **Pause/Resume Scanning:** Use the pause and resume buttons to control the live scanning of Wi-Fi networks.
38-
* **Filtering:** Use the filter options to narrow down the list of networks based on criteria like Wi-Fi band, signal strength, or security type.
3939
* **Export Access Point Details:** You can export the details of the scanned access points for offline analysis. This option is usually found in the application's menu.
4040

41+
## Filtering
42+
43+
The filter dialog lets you focus on Wi-Fi networks that matter most to you by combining multiple filters.
44+
45+
**Available filter options:**
46+
47+
- **SSID:** Filter networks by their name (SSID). Enter all or part of a network name to show only matching networks.
48+
- **WiFi Band:** Select which Wi-Fi bands to display (2.4 GHz, 5 GHz, 6 GHz). This option is available in the Access Points view.
49+
- **Signal Strength:** Show only networks within a specific signal strength range.
50+
- **Security Type:** Filter networks by their security protocol (e.g. WPA2, WPA3, etc).
51+
52+
**Filter dialog actions:**
53+
54+
- **Apply:** Apply the selected filters to update the network list.
55+
- **Reset:** Clear all filters and return to the default view.
56+
- **Close:** Close the filter dialog without making changes.
57+
4158
## Settings and Customization
4259

4360
WiFiAnalyzer offers several options to customize your experience. These are typically found in the app's settings menu.
4461

4562
* **Themes:** Choose between Dark, Light, and System themes to match your preference.
4663
* **Access Point View:** You can switch between a complete view with all details for each access point, or a compact view that shows only the most essential information.
64+
* **Connection View:** Select the layout for displaying connection details (detailed or compact view).
4765

4866
### Advanced Settings
4967

@@ -83,10 +101,12 @@ The channel graph visualizes the Wi-Fi channels and the access points on them.
83101

84102
* **X-axis:** Wi-Fi channels.
85103
* **Y-axis:** Signal strength (dBm).
86-
* **Each shape:** Represents an access point's signal. The width of the shape shows the channel width (e.g., 20, 40, or 80 MHz) it's using.
104+
* **Each shape:** Represents an access point's signal. The width of the shape shows the channel width (20, 40, 80, 160 or 320 MHz) it's using.
87105

88106
An ideal Wi-Fi setup has your access point on a channel with little to no overlap from other networks. Look for channels that are less crowded to improve your Wi-Fi performance.
89107

108+
**Note:** On 5/6 GHz bands, pinch to zoom (in/out) and swipe (left/right) to scroll the channel graph’s X-axis.
109+
90110
### Time Graph
91111

92112
This graph shows the signal strength of a selected access point over time. It's useful for:

app/build.gradle

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,20 @@ dependencies {
4949
testImplementation 'com.googlecode.junit-toolbox:junit-toolbox:2.4'
5050
testImplementation 'junit:junit:4.13.2'
5151
testImplementation 'org.mockito:mockito-core:5.21.0'
52-
testImplementation 'org.mockito.kotlin:mockito-kotlin:6.1.0'
53-
testImplementation 'org.robolectric:robolectric:4.16'
52+
testImplementation 'org.mockito.kotlin:mockito-kotlin:6.2.3'
53+
testImplementation 'org.robolectric:robolectric:4.16.1'
5454
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
5555
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
5656
testImplementation 'org.slf4j:slf4j-simple:2.0.17'
57-
testImplementation 'org.assertj:assertj-core:3.27.6'
57+
testImplementation 'org.assertj:assertj-core:3.27.7'
58+
testImplementation 'org.hamcrest:hamcrest:3.0'
5859
// Android Test Dependencies
5960
androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'
6061
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.7.0'
6162
androidTestImplementation 'androidx.test.ext:junit-ktx:1.3.0'
6263
androidTestImplementation 'androidx.test:rules:1.7.0'
63-
androidTestImplementation 'org.assertj:assertj-core:3.27.6'
64+
androidTestImplementation 'org.assertj:assertj-core:3.27.7'
65+
androidTestImplementation 'org.hamcrest:hamcrest:3.0'
6466
}
6567

6668
android {
@@ -89,7 +91,7 @@ android {
8991
release {
9092
minifyEnabled = true
9193
shrinkResources = true
92-
proguardFiles getDefaultProguardFile("proguard-android.txt")
94+
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt")
9395
signingConfig
9496
}
9597
debug {
@@ -231,3 +233,8 @@ def static writeProperties(propertiesFile, properties) {
231233
properties.store(writer, "Build Properties")
232234
writer.close()
233235
}
236+
237+
configurations.all {
238+
exclude group: 'org.hamcrest', module: 'hamcrest-core'
239+
exclude group: 'org.hamcrest', module: 'hamcrest-library'
240+
}

app/build.properties

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#Build Properties
2-
#Thu Jan 01 14:06:26 EST 2026
3-
version_build=42
2+
#Fri Jan 30 18:31:23 EST 2026
3+
version_build=5
44
version_major=3
55
version_minor=2
6-
version_patch=1
7-
version_store=70
6+
version_patch=2
7+
version_store=71

app/src/androidTest/kotlin/com/vrem/wifianalyzer/ConnectionInstrumentedTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import androidx.test.espresso.assertion.ViewAssertions.matches
2323
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
2424
import androidx.test.espresso.matcher.ViewMatchers.withId
2525
import androidx.test.espresso.matcher.ViewMatchers.withText
26-
import org.hamcrest.Matchers.matchesPattern
26+
import org.hamcrest.Matchers
2727

2828
internal class ConnectionInstrumentedTest : Runnable {
2929
override fun run() {
@@ -39,7 +39,7 @@ internal class ConnectionInstrumentedTest : Runnable {
3939

4040
private fun verifyIpAddressDisplayed() {
4141
val ipv4Pattern = "\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b"
42-
onView(withText(matchesPattern(ipv4Pattern))).check(matches(isDisplayed()))
42+
onView(withText(Matchers.matchesPattern(ipv4Pattern))).check(matches(isDisplayed()))
4343
}
4444

4545
private fun verifyConnectionPopup() {

0 commit comments

Comments
 (0)