diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2c2c478 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# Android Studio +.idea/ +*.iml +*.iws +*.ipr + +# Gradle +.gradle/ +build/ +local.properties + +# OS generated files +.DS_Store +Thumbs.db + +# Compiled class files +*.class + +# Log files +*.log + +# Kotlin build files +out/ + +# Android specific +bin/ +gen/ +captures/ +.externalNativeBuild/ +.cxx/ + +# Dependency directories +node_modules/ + +# Virtual environment +venv/ +.env + +# Misc +*.swp +*.swo \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..b8f2879 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,43 @@ +plugins { + id 'com.android.application' + id 'kotlin-android' +} + +android { + compileSdkVersion 33 + defaultConfig { + applicationId "com.example.wifiscanner" + minSdkVersion 29 + targetSdkVersion 33 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + implementation 'androidx.core:core-ktx:1.9.0' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.8.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + + // Testing dependencies + testImplementation 'junit:junit:4.13.2' + testImplementation 'org.mockito:mockito-core:4.8.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/example/wifiscanner/WifiNetwork.kt b/app/src/main/kotlin/com/example/wifiscanner/WifiNetwork.kt new file mode 100644 index 0000000..1ed0d1b --- /dev/null +++ b/app/src/main/kotlin/com/example/wifiscanner/WifiNetwork.kt @@ -0,0 +1,8 @@ +package com.example.wifiscanner + +data class WifiNetwork( + val ssid: String, + val bssid: String, + val signalStrength: Int, + val securityType: String +) \ No newline at end of file diff --git a/app/src/main/kotlin/com/example/wifiscanner/WifiNetworkAdapter.kt b/app/src/main/kotlin/com/example/wifiscanner/WifiNetworkAdapter.kt new file mode 100644 index 0000000..33657ac --- /dev/null +++ b/app/src/main/kotlin/com/example/wifiscanner/WifiNetworkAdapter.kt @@ -0,0 +1,24 @@ +package com.example.wifiscanner + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView + +class WifiNetworkAdapter(private val networks: List) : + RecyclerView.Adapter() { + + class WifiNetworkViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WifiNetworkViewHolder { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.item_wifi_network, parent, false) + return WifiNetworkViewHolder(view) + } + + override fun onBindViewHolder(holder: WifiNetworkViewHolder, position: Int) { + // Placeholder for future implementation + } + + override fun getItemCount(): Int = networks.size +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/example/wifiscanner/WifiScannerActivity.kt b/app/src/main/kotlin/com/example/wifiscanner/WifiScannerActivity.kt new file mode 100644 index 0000000..0f2a6a5 --- /dev/null +++ b/app/src/main/kotlin/com/example/wifiscanner/WifiScannerActivity.kt @@ -0,0 +1,88 @@ +package com.example.wifiscanner + +import android.Manifest +import android.content.Context +import android.content.pm.PackageManager +import android.net.wifi.WifiManager +import android.os.Bundle +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.LinearLayoutManager +import com.google.android.material.button.MaterialButton +import com.google.android.material.recyclerview.RecyclerView + +class WifiScannerActivity : AppCompatActivity() { + + companion object { + private const val LOCATION_PERMISSION_REQUEST_CODE = 1001 + } + + private lateinit var wifiManager: WifiManager + private lateinit var scanButton: MaterialButton + private lateinit var recyclerView: RecyclerView + private lateinit var wifiNetworkAdapter: WifiNetworkAdapter + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_wifi_scanner) + + // Initialize WiFi Manager + wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager + + // Setup RecyclerView + recyclerView = findViewById(R.id.rv_wifi_networks) + recyclerView.layoutManager = LinearLayoutManager(this) + wifiNetworkAdapter = WifiNetworkAdapter(emptyList()) + recyclerView.adapter = wifiNetworkAdapter + + // Setup Scan Button + scanButton = findViewById(R.id.btn_scan_wifi) + scanButton.setOnClickListener { + performWifiScan() + } + } + + private fun performWifiScan() { + // Check and request permissions + if (checkLocationPermission()) { + // Actual scanning logic will be implemented in future tasks + Toast.makeText(this, "Scanning for WiFi networks...", Toast.LENGTH_SHORT).show() + } + } + + private fun checkLocationPermission(): Boolean { + // Check if location permissions are granted + return if (ContextCompat.checkSelfPermission( + this, + Manifest.permission.ACCESS_FINE_LOCATION + ) != PackageManager.PERMISSION_GRANTED + ) { + // Request permissions + ActivityCompat.requestPermissions( + this, + arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), + LOCATION_PERMISSION_REQUEST_CODE + ) + false + } else { + true + } + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + performWifiScan() + } else { + Toast.makeText(this, "Location permission is required for WiFi scanning", Toast.LENGTH_SHORT).show() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_wifi_scanner.xml b/app/src/main/res/layout/activity_wifi_scanner.xml new file mode 100644 index 0000000..c6a63ee --- /dev/null +++ b/app/src/main/res/layout/activity_wifi_scanner.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_wifi_network.xml b/app/src/main/res/layout/item_wifi_network.xml new file mode 100644 index 0000000..6f38425 --- /dev/null +++ b/app/src/main/res/layout/item_wifi_network.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/test/kotlin/com/example/wifiscanner/WifiScannerActivityTest.kt b/app/src/test/kotlin/com/example/wifiscanner/WifiScannerActivityTest.kt new file mode 100644 index 0000000..6cfd0b1 --- /dev/null +++ b/app/src/test/kotlin/com/example/wifiscanner/WifiScannerActivityTest.kt @@ -0,0 +1,50 @@ +package com.example.wifiscanner + +import android.content.Context +import android.net.wifi.WifiManager +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +import org.mockito.Mockito.verify +import org.mockito.Mockito.mock + +@RunWith(MockitoJUnitRunner::class) +class WifiScannerActivityTest { + + @Mock + private lateinit var mockContext: Context + + @Mock + private lateinit var mockWifiManager: WifiManager + + private lateinit var wifiScannerActivity: WifiScannerActivity + + @Before + fun setup() { + // Setup mocks and initialize activity + wifiScannerActivity = WifiScannerActivity() + } + + @Test + fun testScanButtonExists() { + // Verify that the scan button is present in the layout + val scanButton = wifiScannerActivity.findViewById(R.id.btn_scan_wifi) + assert(scanButton != null) { "Scan button should be present in the layout" } + } + + @Test + fun testRecyclerViewExists() { + // Verify that the RecyclerView is present in the layout + val recyclerView = wifiScannerActivity.findViewById(R.id.rv_wifi_networks) + assert(recyclerView != null) { "RecyclerView should be present in the layout" } + } + + @Test + fun testWifiNetworkAdapterInitialization() { + // Verify that the WiFi network adapter is initialized with an empty list + val recyclerView = wifiScannerActivity.findViewById(R.id.rv_wifi_networks) + assert(recyclerView.adapter is WifiNetworkAdapter) { "Adapter should be an instance of WifiNetworkAdapter" } + } +} \ No newline at end of file