diff --git a/app/build.gradle b/app/build.gradle index feb4408..6631402 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,6 @@ buildscript { repositories { mavenCentral() - jcenter() } dependencies { @@ -15,6 +14,7 @@ buildscript { apply plugin: 'com.android.application' apply plugin: 'spoon' apply plugin: 'com.github.triplet.play' +apply plugin: 'org.jetbrains.kotlin.android' play { track = 'beta' @@ -34,11 +34,11 @@ android { targetSdkVersion targetSdkVer // When updating these, remember to update the vars in the root build.gradle - versionName "0.4.5.3" - versionCode 21 + versionName "0.4.6" + versionCode 23 archivesBaseName = "AndroidNetworkTools" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } //check if the keystore details are defined in gradle.properties (this is so the key is not in github) @@ -73,13 +73,13 @@ spoon { } dependencies { - implementation "com.android.support:appcompat-v7:$supportLibVer" - implementation "com.android.support:design:$supportLibVer" + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.8.0' implementation project(':library') - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13.2' androidTestImplementation 'com.squareup.spoon:spoon-client:1.6.4' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' - androidTestImplementation('com.android.support.test.espresso:espresso-intents:2.2') + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + androidTestImplementation('androidx.test.espresso:espresso-intents:3.5.1') } diff --git a/app/src/androidTest/java/com/stealthcotper/networktools/MainActivityTest.java b/app/src/androidTest/java/com/stealthcotper/networktools/MainActivityTest.java index acfb46a..9ec02b4 100644 --- a/app/src/androidTest/java/com/stealthcotper/networktools/MainActivityTest.java +++ b/app/src/androidTest/java/com/stealthcotper/networktools/MainActivityTest.java @@ -4,8 +4,8 @@ * Created by matthew on 20/12/16. */ -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.rule.ActivityTestRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; import android.view.WindowManager; import com.squareup.spoon.Spoon; @@ -15,14 +15,14 @@ import org.junit.Test; import org.junit.runner.RunWith; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.clearText; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard; -import static android.support.test.espresso.action.ViewActions.typeText; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.clearText; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; +import static androidx.test.espresso.action.ViewActions.typeText; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; @RunWith(AndroidJUnit4.class) public class MainActivityTest { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bbbe649..3564032 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,29 +1,27 @@ + android:installLocation="auto"> - + - - - - - - - - + android:supportsRtl="true" + android:theme="@style/AppTheme"> + + + + + + + diff --git a/app/src/main/java/com/stealthcotper/networktools/ANTApplication.java b/app/src/main/java/com/stealthcotper/networktools/ANTApplication.kt similarity index 69% rename from app/src/main/java/com/stealthcotper/networktools/ANTApplication.java rename to app/src/main/java/com/stealthcotper/networktools/ANTApplication.kt index 0dc91c5..07aa0f2 100644 --- a/app/src/main/java/com/stealthcotper/networktools/ANTApplication.java +++ b/app/src/main/java/com/stealthcotper/networktools/ANTApplication.kt @@ -1,16 +1,14 @@ -package com.stealthcotper.networktools; +package com.stealthcotper.networktools -import android.app.Application; +import android.app.Application -public class ANTApplication extends Application { - - @Override - public void onCreate() { - initStrictMode(); - super.onCreate(); +class ANTApplication : Application() { + override fun onCreate() { + initStrictMode() + super.onCreate() } - private void initStrictMode() { + private fun initStrictMode() { if (BuildConfig.DEBUG) { // Let's be super strict so that we can discover bugs during testing @@ -28,6 +26,4 @@ private void initStrictMode() { // .build()); } } - - -} +} \ No newline at end of file diff --git a/app/src/main/java/com/stealthcotper/networktools/MainActivity.java b/app/src/main/java/com/stealthcotper/networktools/MainActivity.java deleted file mode 100644 index b3c33d1..0000000 --- a/app/src/main/java/com/stealthcotper/networktools/MainActivity.java +++ /dev/null @@ -1,329 +0,0 @@ -package com.stealthcotper.networktools; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.text.TextUtils; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ScrollView; -import android.widget.TextView; - -import com.stealthcopter.networktools.ARPInfo; -import com.stealthcopter.networktools.IPTools; -import com.stealthcopter.networktools.Ping; -import com.stealthcopter.networktools.PortScan; -import com.stealthcopter.networktools.SubnetDevices; -import com.stealthcopter.networktools.WakeOnLan; -import com.stealthcopter.networktools.ping.PingResult; -import com.stealthcopter.networktools.ping.PingStats; -import com.stealthcopter.networktools.subnet.Device; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; - -public class MainActivity extends AppCompatActivity { - - private TextView resultText; - private EditText editIpAddress; - private ScrollView scrollView; - private Button pingButton; - private Button wolButton; - private Button portScanButton; - private Button subnetDevicesButton; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - - resultText = findViewById(R.id.resultText); - editIpAddress = findViewById(R.id.editIpAddress); - scrollView = findViewById(R.id.scrollView1); - pingButton = findViewById(R.id.pingButton); - wolButton = findViewById(R.id.wolButton); - portScanButton = findViewById(R.id.portScanButton); - subnetDevicesButton = findViewById(R.id.subnetDevicesButton); - - InetAddress ipAddress = IPTools.getLocalIPv4Address(); - if (ipAddress != null){ - editIpAddress.setText(ipAddress.getHostAddress()); - } - - findViewById(R.id.pingButton).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new Thread(new Runnable() { - @Override - public void run() { - try { - doPing(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }).start(); - } - }); - - findViewById(R.id.wolButton).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new Thread(new Runnable() { - @Override - public void run() { - try { - doWakeOnLan(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }).start(); - } - }); - - findViewById(R.id.portScanButton).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new Thread(new Runnable() { - @Override - public void run() { - try { - doPortScan(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }).start(); - } - }); - - findViewById(R.id.subnetDevicesButton).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new Thread(new Runnable() { - @Override - public void run() { - try { - findSubnetDevices(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }).start(); - } - }); - - } - - private void appendResultsText(final String text) { - runOnUiThread(new Runnable() { - @Override - public void run() { - resultText.append(text + "\n"); - scrollView.post(new Runnable() { - @Override - public void run() { - scrollView.fullScroll(View.FOCUS_DOWN); - } - }); - } - }); - } - - private void setEnabled(final View view, final boolean enabled) { - runOnUiThread(new Runnable() { - @Override - public void run() { - if (view != null) { - view.setEnabled(enabled); - } - } - }); - } - - private void doPing() throws Exception { - String ipAddress = editIpAddress.getText().toString(); - - if (TextUtils.isEmpty(ipAddress)) { - appendResultsText("Invalid Ip Address"); - return; - } - - setEnabled(pingButton, false); - - // Perform a single synchronous ping - PingResult pingResult = null; - try { - pingResult = Ping.onAddress(ipAddress).setTimeOutMillis(1000).doPing(); - } catch (UnknownHostException e) { - e.printStackTrace(); - appendResultsText(e.getMessage()); - setEnabled(pingButton, true); - return; - } - - - appendResultsText("Pinging Address: " + pingResult.getAddress().getHostAddress()); - appendResultsText("HostName: " + pingResult.getAddress().getHostName()); - appendResultsText(String.format("%.2f ms", pingResult.getTimeTaken())); - - - // Perform an asynchronous ping - Ping.onAddress(ipAddress).setTimeOutMillis(1000).setTimes(5).doPing(new Ping.PingListener() { - @Override - public void onResult(PingResult pingResult) { - if (pingResult.isReachable) { - appendResultsText(String.format("%.2f ms", pingResult.getTimeTaken())); - } else { - appendResultsText(getString(R.string.timeout)); - } - } - - @Override - public void onFinished(PingStats pingStats) { - appendResultsText(String.format("Pings: %d, Packets lost: %d", - pingStats.getNoPings(), pingStats.getPacketsLost())); - appendResultsText(String.format("Min/Avg/Max Time: %.2f/%.2f/%.2f ms", - pingStats.getMinTimeTaken(), pingStats.getAverageTimeTaken(), pingStats.getMaxTimeTaken())); - setEnabled(pingButton, true); - } - - @Override - public void onError(Exception e) { - // TODO: STUB METHOD - setEnabled(pingButton, true); - } - }); - - } - - private void doWakeOnLan() throws IllegalArgumentException { - String ipAddress = editIpAddress.getText().toString(); - - if (TextUtils.isEmpty(ipAddress)) { - appendResultsText("Invalid Ip Address"); - return; - } - - setEnabled(wolButton, false); - - appendResultsText("IP address: " + ipAddress); - - // Get mac address from IP (using arp cache) - String macAddress = ARPInfo.getMACFromIPAddress(ipAddress); - - if (macAddress == null) { - appendResultsText("Could not fromIPAddress MAC address, cannot send WOL packet without it."); - setEnabled(wolButton, true); - return; - } - - appendResultsText("MAC address: " + macAddress); - appendResultsText("IP address2: " + ARPInfo.getIPAddressFromMAC(macAddress)); - - // Send Wake on lan packed to ip/mac - try { - WakeOnLan.sendWakeOnLan(ipAddress, macAddress); - appendResultsText("WOL Packet sent"); - } catch (IOException e) { - appendResultsText(e.getMessage()); - e.printStackTrace(); - } finally { - setEnabled(wolButton, true); - } - } - - private void doPortScan() throws Exception { - String ipAddress = editIpAddress.getText().toString(); - - if (TextUtils.isEmpty(ipAddress)) { - appendResultsText("Invalid Ip Address"); - setEnabled(portScanButton, true); - return; - } - - setEnabled(portScanButton, false); - - // Perform synchronous port scan - appendResultsText("PortScanning IP: " + ipAddress); - ArrayList openPorts = PortScan.onAddress(ipAddress).setPort(21).setMethodTCP().doScan(); - - final long startTimeMillis = System.currentTimeMillis(); - - // Perform an asynchronous port scan - PortScan portScan = PortScan.onAddress(ipAddress).setPortsAll().setMethodTCP().doScan(new PortScan.PortListener() { - @Override - public void onResult(int portNo, boolean open) { - if (open) appendResultsText("Open: " + portNo); - } - - @Override - public void onFinished(ArrayList openPorts) { - appendResultsText("Open Ports: " + openPorts.size()); - appendResultsText("Time Taken: " + ((System.currentTimeMillis() - startTimeMillis)/1000.0f)); - setEnabled(portScanButton, true); - } - }); - - // Below is example of how to cancel a running scan - // portScan.cancel(); - } - - - private void findSubnetDevices() { - - setEnabled(subnetDevicesButton, false); - - final long startTimeMillis = System.currentTimeMillis(); - - SubnetDevices subnetDevices = SubnetDevices.fromLocalAddress().findDevices(new SubnetDevices.OnSubnetDeviceFound() { - @Override - public void onDeviceFound(Device device) { - appendResultsText("Device: " + device.ip+" "+ device.hostname); - } - - @Override - public void onFinished(ArrayList devicesFound) { - float timeTaken = (System.currentTimeMillis() - startTimeMillis)/1000.0f; - appendResultsText("Devices Found: " + devicesFound.size()); - appendResultsText("Finished "+timeTaken+" s"); - setEnabled(subnetDevicesButton, true); - } - }); - - // Below is example of how to cancel a running scan - // subnetDevices.cancel(); - - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.menu_main, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.action_github) { - Intent i = new Intent(Intent.ACTION_VIEW); - i.setData(Uri.parse(getString(R.string.github_url))); - startActivity(i); - return true; - } else { - return super.onOptionsItemSelected(item); - } - } - -} diff --git a/app/src/main/java/com/stealthcotper/networktools/MainActivity.kt b/app/src/main/java/com/stealthcotper/networktools/MainActivity.kt new file mode 100644 index 0000000..0e08425 --- /dev/null +++ b/app/src/main/java/com/stealthcotper/networktools/MainActivity.kt @@ -0,0 +1,296 @@ +package com.stealthcotper.networktools + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import android.text.TextUtils +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.widget.Button +import android.widget.EditText +import android.widget.ScrollView +import android.widget.TextView +import com.stealthcopter.networktools.* +import com.stealthcopter.networktools.Ping.PingListener +import com.stealthcopter.networktools.PortScan.PortListener +import com.stealthcopter.networktools.SubnetDevices.OnSubnetDeviceFound +import com.stealthcopter.networktools.ping.PingResult +import com.stealthcopter.networktools.ping.PingStats +import com.stealthcopter.networktools.subnet.Device +import java.io.IOException +import java.net.UnknownHostException + +class MainActivity : AppCompatActivity() { + private var resultText: TextView? = null + private var editIpAddress: EditText? = null + private var scrollView: ScrollView? = null + private var pingButton: Button? = null + private var wolButton: Button? = null + private var portScanButton: Button? = null + private var subnetDevicesButton: Button? = null + private var clearLogButton: Button? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + val toolbar = findViewById(R.id.toolbar) + setSupportActionBar(toolbar) + resultText = findViewById(R.id.resultText) + editIpAddress = findViewById(R.id.editIpAddress) + scrollView = findViewById(R.id.scrollView1) + pingButton = findViewById(R.id.pingButton) + wolButton = findViewById(R.id.wolButton) + portScanButton = findViewById(R.id.portScanButton) + subnetDevicesButton = findViewById(R.id.subnetDevicesButton) + clearLogButton = findViewById(R.id.clearLogButton) + + + val ipAddress = IPTools.localIPv4Address + if (ipAddress != null) { + editIpAddress?.setText(ipAddress.hostAddress) + } + + clearLogButton?.setOnClickListener{ + resultText?.text="" + } + + pingButton?.setOnClickListener { + Thread { + try { + doPing() + } catch (e: Exception) { + e.printStackTrace() + } + }.start() + } + + wolButton?.setOnClickListener { + Thread { + try { + doWakeOnLan() + } catch (e: Exception) { + e.printStackTrace() + } + }.start() + } + + portScanButton?.setOnClickListener { + Thread { + try { + doPortScan() + } catch (e: Exception) { + e.printStackTrace() + } + }.start() + } + + subnetDevicesButton?.setOnClickListener { + Thread { + try { + findSubnetDevices() + } catch (e: Exception) { + e.printStackTrace() + } + }.start() + } + } + + private fun appendResultsText(text: String?) { + runOnUiThread { + resultText!!.append( + """ + $text + """.trimIndent() + ) + scrollView!!.post { scrollView!!.fullScroll(View.FOCUS_DOWN) } + } + } + + private fun setEnabled(view: View?, enabled: Boolean) { + runOnUiThread { + if (view != null) { + view.isEnabled = enabled + } + } + } + + @Throws(Exception::class) + private fun doPing() { + val ipAddress = editIpAddress!!.text.toString() + if (TextUtils.isEmpty(ipAddress)) { + appendResultsText("Invalid Ip Address") + return + } + setEnabled(pingButton, false) + + // Perform a single synchronous ping + var pingResult: PingResult? = null + pingResult = try { + Ping.onAddress(ipAddress).setTimeOutMillis(1000).doPing() + } catch (e: UnknownHostException) { + e.printStackTrace() + appendResultsText(e.message) + setEnabled(pingButton, true) + return + } + appendResultsText("Pinging Address: " + pingResult?.address?.hostAddress) + appendResultsText("\n") + appendResultsText("HostName: " + pingResult?.address?.hostName) + appendResultsText("\n") + appendResultsText(String.format("%.2f ms", pingResult?.timeTaken)) + + + // Perform an asynchronous ping + Ping.onAddress(ipAddress).setTimeOutMillis(1000).setTimes(5).doPing(object : PingListener { + override fun onResult(pingResult: PingResult?) { + if (pingResult?.isReachable == true) { + appendResultsText("\n") + appendResultsText(String.format("%.2f ms", pingResult?.timeTaken)) + } else { + appendResultsText("\n") + appendResultsText(getString(R.string.timeout)) + } + } + + override fun onFinished(pingStats: PingStats?) { + appendResultsText("\n") + appendResultsText( + String.format( + "Pings: %d, Packets lost: %d", + pingStats?.noPings, pingStats?.packetsLost + ) + ) + appendResultsText("\n") + appendResultsText( + String.format( + "Min/Avg/Max Time: %.2f/%.2f/%.2f ms", + pingStats?.minTimeTaken, + pingStats?.averageTimeTaken, + pingStats?.maxTimeTaken + ) + ) + setEnabled(pingButton, true) + } + + override fun onError(e: Exception?) { + setEnabled(pingButton, true) + } + }) + } + + @Throws(IllegalArgumentException::class) + private fun doWakeOnLan() { + val ipAddress = editIpAddress!!.text.toString() + if (TextUtils.isEmpty(ipAddress)) { + appendResultsText("Invalid Ip Address") + return + } + setEnabled(wolButton, false) + appendResultsText("IP address: $ipAddress") + + // Get mac address from IP (using arp cache) + val macAddress = ARPInfo.getMACFromIPAddress(ipAddress) + if (macAddress == null) { + appendResultsText("Could not fromIPAddress MAC address, cannot send WOL packet without it.") + setEnabled(wolButton, true) + return + } + appendResultsText("MAC address: $macAddress") + appendResultsText("IP address2: " + ARPInfo.getIPAddressFromMAC(macAddress)) + + // Send Wake on lan packed to ip/mac + try { + WakeOnLan.sendWakeOnLan(ipAddress, macAddress) + appendResultsText("WOL Packet sent") + } catch (e: IOException) { + appendResultsText(e.message) + e.printStackTrace() + } finally { + setEnabled(wolButton, true) + } + } + + @Throws(Exception::class) + private fun doPortScan() { + val ipAddress = editIpAddress!!.text.toString() + if (TextUtils.isEmpty(ipAddress)) { + appendResultsText("Invalid Ip Address") + setEnabled(portScanButton, true) + return + } + setEnabled(portScanButton, false) + + // Perform synchronous port scan + appendResultsText("PortScanning IP: $ipAddress") + appendResultsText("\n") + val openPorts = PortScan.onAddress(ipAddress).setPort(21).setMethodTCP().doScan() + val startTimeMillis = System.currentTimeMillis() + + // Perform an asynchronous port scan + val portScan = PortScan.onAddress(ipAddress).setPortsAll().setMethodTCP() + .doScan(object : PortListener { + override fun onResult(portNo: Int, open: Boolean) { + if (open) { + appendResultsText("Open: $portNo") + appendResultsText("\n") + } + } + + override fun onFinished(openPorts: java.util.ArrayList?) { + appendResultsText("\n") + appendResultsText("Open Ports: " + openPorts?.size) + appendResultsText("\n") + appendResultsText("Time Taken: " + (System.currentTimeMillis() - startTimeMillis) / 1000.0f + " s") + appendResultsText("\n") + setEnabled(portScanButton, true) + } + }) + + // Below is example of how to cancel a running scan + // portScan.cancel(); + } + + private fun findSubnetDevices() { + setEnabled(subnetDevicesButton, false) + val startTimeMillis = System.currentTimeMillis() + val subnetDevices = + SubnetDevices.fromLocalAddress().findDevices(object : OnSubnetDeviceFound { + override fun onDeviceFound(device: Device?) { + appendResultsText("Device: " + device?.ip + " " + device?.hostname) + appendResultsText("\n") + } + + override fun onFinished(devicesFound: ArrayList?) { + val timeTaken = (System.currentTimeMillis() - startTimeMillis) / 1000.0f + appendResultsText("Devices Found: " + devicesFound?.size) + appendResultsText("\n") + appendResultsText("Finished $timeTaken s") + appendResultsText("\n") + setEnabled(subnetDevicesButton, true) + } + }) + + // Below is example of how to cancel a running scan + // subnetDevices.cancel(); + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + val inflater = menuInflater + inflater.inflate(R.menu.menu_main, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return if (item.itemId == R.id.action_github) { + val i = Intent(Intent.ACTION_VIEW) + i.data = Uri.parse(getString(R.string.github_url)) + startActivity(i) + true + } else { + super.onOptionsItemSelected(item) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index d1609e0..8fac476 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,5 +1,5 @@ - - - - + - + diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index ff6675e..2f96fe9 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -1,6 +1,5 @@ - + tools:showIn="@layout/activity_main"> + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingBottom="@dimen/activity_horizontal_margin"> + android:layout_height="0px" + android:focusable="true" + android:focusableInTouchMode="true" /> - + - + android:inputType="textNoSuggestions" /> + + android:text="@string/ping" />