From 564fc408740440ffd7043cee53c5a032558eb12b Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Mon, 26 Nov 2018 10:23:01 -0800 Subject: [PATCH 01/16] Bump tools --- app/build.gradle | 2 +- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 240904ce..3f6c6e5d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,7 +16,7 @@ sonarqube { android { compileSdkVersion 27 - buildToolsVersion '27.0.2' + buildToolsVersion '28.0.3' defaultConfig { minSdkVersion 14 diff --git a/build.gradle b/build.gradle index 197b6f29..d568a72b 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.2.1' classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.4' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d47e3bac..9e2e115c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Oct 17 17:47:38 EDT 2017 +#Mon Nov 26 10:17:51 PST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip From 669a38cc828bfa81e73d462ed368b1fd595365f0 Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Mon, 26 Nov 2018 11:30:36 -0800 Subject: [PATCH 02/16] Bump deps --- .travis.yml | 2 +- app/build.gradle | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 52c7ec63..81864d7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ jdk: android: components: - tools - - build-tools-27.0.2 + - build-tools-28.0.3 - android-27 - extra-android-m2repository diff --git a/app/build.gradle b/app/build.gradle index 3f6c6e5d..517c28d3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -65,9 +65,9 @@ android { } dependencies { - compile 'com.android.support:support-v4:27.0.2' - compile 'com.android.support:appcompat-v7:27.0.2' - compile 'com.squareup.okhttp3:okhttp:3.9.1' + compile 'com.android.support:support-v4:27.1.1' + compile 'com.android.support:appcompat-v7:27.1.1' + compile 'com.squareup.okhttp3:okhttp:3.10.0' compile 'jcifs:jcifs:1.3.17' compile 'dnsjava:dnsjava:2.1.7' //This does absolutely nothing From 8a6bb4739b5fa6eeb7fa0e30cd866c7fe652a489 Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Mon, 14 Jan 2019 23:44:26 -0800 Subject: [PATCH 03/16] Some cleanup and regex fixes, bump gradle to newer version --- .../com/aaronjwood/portauthority/activity/HostActivity.java | 2 +- .../com/aaronjwood/portauthority/activity/MainActivity.java | 2 +- .../java/com/aaronjwood/portauthority/async/WolAsyncTask.java | 2 +- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/aaronjwood/portauthority/activity/HostActivity.java b/app/src/main/java/com/aaronjwood/portauthority/activity/HostActivity.java index be9f7b44..cb9efd83 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/activity/HostActivity.java +++ b/app/src/main/java/com/aaronjwood/portauthority/activity/HostActivity.java @@ -40,7 +40,7 @@ public abstract class HostActivity extends AppCompatActivity implements HostAsyn protected int layout; protected ArrayAdapter adapter; protected ListView portList; - protected final List ports = Collections.synchronizedList(new ArrayList()); + protected final List ports = Collections.synchronizedList(new ArrayList<>()); protected ProgressDialog scanProgressDialog; protected Dialog portRangeDialog; protected Handler handler; diff --git a/app/src/main/java/com/aaronjwood/portauthority/activity/MainActivity.java b/app/src/main/java/com/aaronjwood/portauthority/activity/MainActivity.java index 5283ebc1..78013f15 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/activity/MainActivity.java +++ b/app/src/main/java/com/aaronjwood/portauthority/activity/MainActivity.java @@ -78,7 +78,7 @@ public final class MainActivity extends AppCompatActivity implements MainAsyncRe private Handler scanHandler; private IntentFilter intentFilter = new IntentFilter(); private HostAdapter hostAdapter; - private List hosts = Collections.synchronizedList(new ArrayList()); + private List hosts = Collections.synchronizedList(new ArrayList<>()); private Database db; private DownloadAsyncTask ouiTask; private DownloadAsyncTask portTask; diff --git a/app/src/main/java/com/aaronjwood/portauthority/async/WolAsyncTask.java b/app/src/main/java/com/aaronjwood/portauthority/async/WolAsyncTask.java index 2e5e34de..ad24b639 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/async/WolAsyncTask.java +++ b/app/src/main/java/com/aaronjwood/portauthority/async/WolAsyncTask.java @@ -21,7 +21,7 @@ protected Void doInBackground(String... params) { String ip = params[1]; byte[] macBytes = new byte[6]; - String[] macHex = mac.split("(:|-)"); + String[] macHex = mac.split("([:\\-])"); for (int i = 0; i < 6; i++) { macBytes[i] = (byte) Integer.parseInt(macHex[i], 16); } diff --git a/build.gradle b/build.gradle index d568a72b..e8a837e8 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.3.0' classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.4' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9e2e115c..7f8c65e6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Nov 26 10:17:51 PST 2018 +#Mon Jan 14 23:33:13 PST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip From 1699fdcfce1907b456fde74dd0b4936f122040da Mon Sep 17 00:00:00 2001 From: PanderMusubi Date: Thu, 26 Sep 2019 17:55:15 +0200 Subject: [PATCH 04/16] Added Dutch translation --- app/src/main/res/values-nl/strings.xml | 59 ++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 app/src/main/res/values-nl/strings.xml diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml new file mode 100644 index 00000000..6f7a6111 --- /dev/null +++ b/app/src/main/res/values-nl/strings.xml @@ -0,0 +1,59 @@ + + + + Port Authority + Instellingen + MAC + Leverancier + LAN IP + WAN IP + Ophalen… + Signaal/Snelheid + Ontdek hosts + SSID + BSSID + Scan welbekende poorten + Scan poortbereik + Reset poortbereik + Open poorten + Beginpoort + Eindpoort + Wifi is niet ingeschakeld + Geen wifiverbinding + URL/IP + WAARSCHUWING + Domeinnaam + DNS-lookup + Wakker maken + Wakker aan het maken %1$s… + IP-adres + Ophalen van DNS-records… + Voer een domein in en selecteer een recordtype + Je bent niet verbonden met een lokaal netwerk + Je bent niet verbonden met een wifinetwerk! + %1$ddBm/%2$dMbps + Scannen naar hosts + %1$d hosts in je subnet + Sorteer + Op hostnaam + Op leverancier + Kopieer hostnaam + Kopieer IP + Kopieer MAC + Opvragen MAC-leverancier is mislukt + Openen database is mislukt + Gegevens aan het downloaden + Opgraven van aantal hosts in dit subnet is mislukt + Opvragen signaalsterkte is mislukt + Opvragen verbindingssnelheid is mislukt + Opvragen SSID is mislukt + Opvragen BSSID is mislukt + Opvragen WifiManager van dit apparaat is mislukt + Geen wifi-interface gevonden + + Houd er rekening mee dat het uitvoeren van poortscans tegen openbare servers normaal gesproken als kwaadaardig wordt beschouwd. + Bovendien zal het uitvoeren van dit soort scans over het netwerk van je provider in plaats van je eigen wifiverbinding trager verlopen en soms onnauwkeurige resultaten opleveren als gevolg van traffic shaping. + Je provider kan ook het verkeer dat door deze scan wordt gegenereerd als kwaadaardig beschouwen. + + + From e6210dd951d501aa5e89bfbca41dc0c1f464afef Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Wed, 1 Jan 2020 22:20:27 -0800 Subject: [PATCH 05/16] Bump deps and target SDK --- app/build.gradle | 9 ++++----- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 517c28d3..865d94dd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,12 +15,12 @@ sonarqube { } android { - compileSdkVersion 27 + compileSdkVersion 29 buildToolsVersion '28.0.3' defaultConfig { minSdkVersion 14 - targetSdkVersion 27 + targetSdkVersion 29 versionCode 55 versionName "2.2.8" applicationId "com.aaronjwood.portauthority" @@ -65,12 +65,11 @@ android { } dependencies { - compile 'com.android.support:support-v4:27.1.1' - compile 'com.android.support:appcompat-v7:27.1.1' + compile 'com.android.support:support-v4:28.0.0' + compile 'com.android.support:appcompat-v7:28.0.0' compile 'com.squareup.okhttp3:okhttp:3.10.0' compile 'jcifs:jcifs:1.3.17' compile 'dnsjava:dnsjava:2.1.7' - //This does absolutely nothing releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4' testCompile 'junit:junit:4.12' diff --git a/build.gradle b/build.gradle index e8a837e8..87039655 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:3.5.3' classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.4' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7f8c65e6..e52b72fa 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Jan 14 23:33:13 PST 2019 +#Wed Jan 01 19:13:52 PST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip From e1bcdaa25dda9529cc8d567817e83279967cabb1 Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Wed, 1 Jan 2020 22:20:34 -0800 Subject: [PATCH 06/16] Apply workaround for getting ARP entries for Android 10+ --- .../async/ScanHostsAsyncTask.java | 177 ++++++++++++------ 1 file changed, 124 insertions(+), 53 deletions(-) diff --git a/app/src/main/java/com/aaronjwood/portauthority/async/ScanHostsAsyncTask.java b/app/src/main/java/com/aaronjwood/portauthority/async/ScanHostsAsyncTask.java index f648a11b..a348e65b 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/async/ScanHostsAsyncTask.java +++ b/app/src/main/java/com/aaronjwood/portauthority/async/ScanHostsAsyncTask.java @@ -1,6 +1,8 @@ package com.aaronjwood.portauthority.async; import android.os.AsyncTask; +import android.os.Build; +import android.util.Pair; import com.aaronjwood.portauthority.db.Database; import com.aaronjwood.portauthority.network.Host; @@ -16,6 +18,8 @@ import java.lang.ref.WeakReference; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -27,6 +31,9 @@ public class ScanHostsAsyncTask extends AsyncTask { private final WeakReference delegate; private Database db; private static final String ARP_TABLE = "/proc/net/arp"; + private static final String IP_CMD = "ip neighbor"; + private static final String NEIGHBOR_INCOMPLETE = "INCOMPLETE"; + private static final String NEIGHBOR_FAILED = "FAILED"; private static final String ARP_INCOMPLETE = "0x0"; private static final String ARP_INACTIVE = "00:00:00:00:00:00"; private static final int NETBIOS_FILE_SERVER = 0x20; @@ -51,14 +58,38 @@ protected Void doInBackground(Integer... params) { int ipv4 = params[0]; int cidr = params[1]; int timeout = params[2]; - MainAsyncResponse activity = delegate.get(); - File file = new File(ARP_TABLE); - if (!file.exists() || !file.canRead()) { - activity.processFinish(new FileNotFoundException("Unable to access device ARP table")); - activity.processFinish(true); - return null; + // Android 10+ doesn't let us access the ARP table. + // Do an early check to see if we can get what we need from the system. + // https://developer.android.com/about/versions/10/privacy/changes#proc-net-filesystem + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + try { + Process ipProc = Runtime.getRuntime().exec(IP_CMD); + ipProc.waitFor(); + if (ipProc.exitValue() != 0) { + activity.processFinish(new IOException("Unable to access ARP entries")); + activity.processFinish(true); + + return null; + } + } catch (IOException | InterruptedException e) { + activity.processFinish(new IOException("Unable to parse ARP entries")); + activity.processFinish(true); + } + } else { + File file = new File(ARP_TABLE); + if (!file.exists()) { + activity.processFinish(new FileNotFoundException("Unable to find ARP table")); + activity.processFinish(true); + + return null; + } + + if (!file.canRead()) { + activity.processFinish(new IOException("Unable to read ARP table")); + activity.processFinish(true); + } } ExecutorService executor = Executors.newCachedThreadPool(); @@ -107,63 +138,103 @@ protected final void onProgressUpdate(Void... params) { final MainAsyncResponse activity = delegate.get(); ExecutorService executor = Executors.newCachedThreadPool(); final AtomicInteger numHosts = new AtomicInteger(0); + List> pairs = new ArrayList<>(); try { - reader = new BufferedReader(new InputStreamReader(new FileInputStream(ARP_TABLE), "UTF-8")); - reader.readLine(); // Skip header. - String line; - - while ((line = reader.readLine()) != null) { - String[] arpLine = line.split("\\s+"); - - final String ip = arpLine[0]; - final String flag = arpLine[2]; - final String macAddress = arpLine[3]; - - if (!ARP_INCOMPLETE.equals(flag) && !ARP_INACTIVE.equals(macAddress)) { - numHosts.incrementAndGet(); - executor.execute(new Runnable() { - - @Override - public void run() { - Host host; - try { - host = new Host(ip, macAddress, db); - } catch (IOException e) { - host = new Host(ip, macAddress); - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Process ipProc = Runtime.getRuntime().exec(IP_CMD); + ipProc.waitFor(); + if (ipProc.exitValue() != 0) { + throw new Exception("Unable to access ARP entries"); + } - MainAsyncResponse activity = delegate.get(); - try { - InetAddress add = InetAddress.getByName(ip); - String hostname = add.getCanonicalHostName(); - host.setHostname(hostname); + reader = new BufferedReader(new InputStreamReader(ipProc.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + String[] neighborLine = line.split("\\s+"); - if (activity != null) { - activity.processFinish(host, numHosts); - } - } catch (UnknownHostException e) { - numHosts.decrementAndGet(); - activity.processFinish(e); - return; + // We don't have a validated ARP entry for this case. + if (neighborLine.length <= 4) { + continue; + } + + String ip = neighborLine[0]; + InetAddress addr = InetAddress.getByName(ip); + if (addr.isLinkLocalAddress() || addr.isLoopbackAddress()) { + continue; + } + + String macAddress = neighborLine[4]; + String state = neighborLine[neighborLine.length - 1]; + + // Determine if the ARP entry is valid. + // https://github.com/sivasankariit/iproute2/blob/master/ip/ipneigh.c + if (!NEIGHBOR_FAILED.equals(state) && !NEIGHBOR_INCOMPLETE.equals(state)) { + pairs.add(new Pair<>(ip, macAddress)); + } + } + } else { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(ARP_TABLE), "UTF-8")); + reader.readLine(); // Skip header. + String line; + + while ((line = reader.readLine()) != null) { + String[] arpLine = line.split("\\s+"); + String ip = arpLine[0]; + String flag = arpLine[2]; + String macAddress = arpLine[3]; + + if (!ARP_INCOMPLETE.equals(flag) && !ARP_INACTIVE.equals(macAddress)) { + pairs.add(new Pair<>(ip, macAddress)); + } + } + } + + numHosts.addAndGet(pairs.size()); + for (Pair pair : pairs) { + String ip = pair.first; + String macAddress = pair.second; + executor.execute(new Runnable() { + + @Override + public void run() { + Host host; + try { + host = new Host(ip, macAddress, db); + } catch (IOException e) { + host = new Host(ip, macAddress); + } + + MainAsyncResponse activity = delegate.get(); + try { + InetAddress add = InetAddress.getByName(ip); + String hostname = add.getCanonicalHostName(); + host.setHostname(hostname); + + if (activity != null) { + activity.processFinish(host, numHosts); } + } catch (UnknownHostException e) { + numHosts.decrementAndGet(); + activity.processFinish(e); + return; + } - try { - NbtAddress[] netbios = NbtAddress.getAllByAddress(ip); - for (NbtAddress addr : netbios) { - if (addr.getNameType() == NETBIOS_FILE_SERVER) { - host.setHostname(addr.getHostName()); - return; - } + try { + NbtAddress[] netbios = NbtAddress.getAllByAddress(ip); + for (NbtAddress addr : netbios) { + if (addr.getNameType() == NETBIOS_FILE_SERVER) { + host.setHostname(addr.getHostName()); + return; } - } catch (UnknownHostException e) { - // It's common that many discovered hosts won't have a NetBIOS entry. } + } catch (UnknownHostException e) { + // It's common that many discovered hosts won't have a NetBIOS entry. } - }); - } + } + }); } - } catch (IOException e) { + } catch (Exception e) { if (activity != null) { activity.processFinish(e); } From 5da6c237e22d67b43e176ae86f013d3ba1fc25a2 Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Wed, 1 Jan 2020 22:43:05 -0800 Subject: [PATCH 07/16] Bump SDK in for CI --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 81864d7d..0ac44119 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ android: components: - tools - build-tools-28.0.3 - - android-27 + - android-29 - extra-android-m2repository env: From 43bc9f207e0ccb40b085fd7080b98533ea7a4181 Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Wed, 1 Jan 2020 23:26:24 -0800 Subject: [PATCH 08/16] Support reading the SSID on Android 8+ --- app/src/main/AndroidManifest.xml | 1 + .../portauthority/activity/MainActivity.java | 36 +++++++++++++++++-- .../portauthority/utils/UserPreference.java | 17 +++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6f79851c..4b1238f9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + = Build.VERSION_CODES.O) { + if (!UserPreference.getLocationPermDiag(context)) { + new AlertDialog.Builder(this, R.style.DialogTheme).setTitle("SSID Access") + .setMessage("Android 8+ now requires location permissions to read the SSID. " + + "If this is not something you're comfortable with just deny the request and go without the functionality.") + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + dialogInterface.dismiss(); + UserPreference.saveLocationPermDiag(context); + } + }) + .setIcon(android.R.drawable.ic_dialog_alert).show().setCanceledOnTouchOutside(false); + } + + if (ContextCompat.checkSelfPermission(context, + Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, + COARSE_LOCATION_REQUEST); + } + } + intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); } @@ -455,7 +485,7 @@ public void run() { Errors.showError(context, resources.getString(R.string.failedSignal)); return; } - + signalStrength.setText(String.format(resources.getString(R.string.signalLink), signal, speed)); signalHandler.postDelayed(this, TIMER_INTERVAL); } diff --git a/app/src/main/java/com/aaronjwood/portauthority/utils/UserPreference.java b/app/src/main/java/com/aaronjwood/portauthority/utils/UserPreference.java index e9f7a0b8..44dfdfd8 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/utils/UserPreference.java +++ b/app/src/main/java/com/aaronjwood/portauthority/utils/UserPreference.java @@ -22,6 +22,7 @@ public class UserPreference { private static final String LAN_SOCKET_TIMEOUT = "lanTimeout"; private static final String WAN_SOCKET_TIMEOUT = "wanTimeout"; private static final String HOST_SOCKET_TIMEOUT = "hostTimeout"; + private static final String LOCATION_PERM_DIAG = "locationPermDiag"; /** * Saves the last used host address for later use. @@ -37,6 +38,22 @@ public static void saveLastUsedHostAddress(@NonNull Context context, @Nullable S } } + /** + * Saves the state of the location permission dialog. + */ + public static void saveLocationPermDiag(@NonNull Context context) { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + preferences.edit().putBoolean(LOCATION_PERM_DIAG, true).apply(); + } + + /** + * Saves the state of the location permission dialog. + */ + public static boolean getLocationPermDiag(@NonNull Context context) { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + return preferences.getBoolean(LOCATION_PERM_DIAG, false); + } + /** * Gets the last used host address or an empty string if there isn't one. */ From 7e424d56ef4f5c4c1f20e8915c1cddec7ccc61d4 Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Wed, 1 Jan 2020 23:35:40 -0800 Subject: [PATCH 09/16] Notify the user first about why we're requesting location permissions --- .../portauthority/activity/MainActivity.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/aaronjwood/portauthority/activity/MainActivity.java b/app/src/main/java/com/aaronjwood/portauthority/activity/MainActivity.java index 0686bb0a..c61915c0 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/activity/MainActivity.java +++ b/app/src/main/java/com/aaronjwood/portauthority/activity/MainActivity.java @@ -1,6 +1,7 @@ package com.aaronjwood.portauthority.activity; import android.Manifest; +import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.BroadcastReceiver; @@ -143,7 +144,8 @@ protected void onCreate(Bundle savedInstanceState) { // Android 8+ now require this permission to read the SSID. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (!UserPreference.getLocationPermDiag(context)) { - new AlertDialog.Builder(this, R.style.DialogTheme).setTitle("SSID Access") + Activity activity = this; + new AlertDialog.Builder(activity, R.style.DialogTheme).setTitle("SSID Access") .setMessage("Android 8+ now requires location permissions to read the SSID. " + "If this is not something you're comfortable with just deny the request and go without the functionality.") .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @@ -151,16 +153,15 @@ protected void onCreate(Bundle savedInstanceState) { public void onClick(DialogInterface dialogInterface, int i) { dialogInterface.dismiss(); UserPreference.saveLocationPermDiag(context); + if (ContextCompat.checkSelfPermission(context, + Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, + COARSE_LOCATION_REQUEST); + } } }) .setIcon(android.R.drawable.ic_dialog_alert).show().setCanceledOnTouchOutside(false); } - - if (ContextCompat.checkSelfPermission(context, - Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, - COARSE_LOCATION_REQUEST); - } } intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); From ae1c33f8183c18db539f86be9dbc6b686e66c003 Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Thu, 2 Jan 2020 00:17:21 -0800 Subject: [PATCH 10/16] Bump versions --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 865d94dd..f8375ead 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,8 +21,8 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 29 - versionCode 55 - versionName "2.2.8" + versionCode 56 + versionName "2.2.10" applicationId "com.aaronjwood.portauthority" setProperty("archivesBaseName", "PortAuthority-$versionName") } From 44c7ed80fec4f20b52131954353bc70ebc6a9bab Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Thu, 2 Jan 2020 00:47:52 -0800 Subject: [PATCH 11/16] Clean up --- .../portauthority/activity/HostActivity.java | 52 +++----- .../activity/LanHostActivity.java | 22 ++- .../portauthority/activity/MainActivity.java | 126 ++++++------------ .../activity/WanHostActivity.java | 8 +- .../async/DownloadAsyncTask.java | 12 +- .../async/ScanHostsAsyncTask.java | 61 ++++----- .../runnable/ScanPortsRunnable.java | 5 +- 7 files changed, 101 insertions(+), 185 deletions(-) diff --git a/app/src/main/java/com/aaronjwood/portauthority/activity/HostActivity.java b/app/src/main/java/com/aaronjwood/portauthority/activity/HostActivity.java index cb9efd83..14375f2b 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/activity/HostActivity.java +++ b/app/src/main/java/com/aaronjwood/portauthority/activity/HostActivity.java @@ -114,7 +114,7 @@ protected void onDestroy() { public void onSaveInstanceState(Bundle savedState) { super.onSaveInstanceState(savedState); - String[] savedList = ports.toArray(new String[ports.size()]); + String[] savedList = ports.toArray(new String[0]); savedState.putStringArray("ports", savedList); } @@ -141,12 +141,9 @@ public void onRestoreInstanceState(Bundle savedInstanceState) { * @param stop Stopping port picker */ protected void resetPortRangeScanClick(final NumberPicker start, final NumberPicker stop) { - portRangeDialog.findViewById(R.id.resetPortRangeScan).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - start.setValue(Constants.MIN_PORT_VALUE); - stop.setValue(Constants.MAX_PORT_VALUE); - } + portRangeDialog.findViewById(R.id.resetPortRangeScan).setOnClickListener(v -> { + start.setValue(Constants.MIN_PORT_VALUE); + stop.setValue(Constants.MAX_PORT_VALUE); }); } @@ -250,13 +247,9 @@ public void onItemClick(AdapterView parent, View view, int position, long id) */ @Override public void processFinish(final int output) { - handler.post(new Runnable() { - - @Override - public void run() { - if (scanProgressDialog != null) { - scanProgressDialog.incrementProgressBy(output); - } + handler.post(() -> { + if (scanProgressDialog != null) { + scanProgressDialog.incrementProgressBy(output); } }); } @@ -307,24 +300,16 @@ private String formatOpenPort(SparseArray entry, int scannedPort, String */ private void addOpenPort(final String port) { setAnimations(); - handler.post(new Runnable() { - - @Override - public void run() { - ports.add(port); - Collections.sort(ports, new Comparator() { - - @Override - public int compare(String lhs, String rhs) { - int left = Integer.parseInt(lhs.substring(0, lhs.indexOf('-') - 1)); - int right = Integer.parseInt(rhs.substring(0, rhs.indexOf('-') - 1)); + handler.post(() -> { + ports.add(port); + Collections.sort(ports, (lhs, rhs) -> { + int left = Integer.parseInt(lhs.substring(0, lhs.indexOf('-') - 1)); + int right = Integer.parseInt(rhs.substring(0, rhs.indexOf('-') - 1)); - return left - right; - } - }); + return left - right; + }); - adapter.notifyDataSetChanged(); - } + adapter.notifyDataSetChanged(); }); } @@ -335,11 +320,6 @@ public int compare(String lhs, String rhs) { * @param Exception */ public void processFinish(final T output) { - handler.post(new Runnable() { - @Override - public void run() { - Errors.showError(getApplicationContext(), output.getLocalizedMessage()); - } - }); + handler.post(() -> Errors.showError(getApplicationContext(), output.getLocalizedMessage())); } } diff --git a/app/src/main/java/com/aaronjwood/portauthority/activity/LanHostActivity.java b/app/src/main/java/com/aaronjwood/portauthority/activity/LanHostActivity.java index ab2dea7c..b3931761 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/activity/LanHostActivity.java +++ b/app/src/main/java/com/aaronjwood/portauthority/activity/LanHostActivity.java @@ -169,23 +169,19 @@ public void onClick(View v) { */ private void setupWol() { Button wakeUpButton = findViewById(R.id.wakeOnLan); - wakeUpButton.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - try { - if (!wifi.isConnectedWifi()) { - Errors.showError(getApplicationContext(), getResources().getString(R.string.notConnectedLan)); - return; - } - } catch (Wireless.NoConnectivityManagerException e) { + wakeUpButton.setOnClickListener(v -> { + try { + if (!wifi.isConnectedWifi()) { Errors.showError(getApplicationContext(), getResources().getString(R.string.notConnectedLan)); return; } - - host.wakeOnLan(); - Toast.makeText(getApplicationContext(), String.format(getResources().getString(R.string.waking), host.getHostname()), Toast.LENGTH_LONG).show(); + } catch (Wireless.NoConnectivityManagerException e) { + Errors.showError(getApplicationContext(), getResources().getString(R.string.notConnectedLan)); + return; } + + host.wakeOnLan(); + Toast.makeText(getApplicationContext(), String.format(getResources().getString(R.string.waking), host.getHostname()), Toast.LENGTH_LONG).show(); }); } diff --git a/app/src/main/java/com/aaronjwood/portauthority/activity/MainActivity.java b/app/src/main/java/com/aaronjwood/portauthority/activity/MainActivity.java index c61915c0..589cb3e2 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/activity/MainActivity.java +++ b/app/src/main/java/com/aaronjwood/portauthority/activity/MainActivity.java @@ -148,16 +148,13 @@ protected void onCreate(Bundle savedInstanceState) { new AlertDialog.Builder(activity, R.style.DialogTheme).setTitle("SSID Access") .setMessage("Android 8+ now requires location permissions to read the SSID. " + "If this is not something you're comfortable with just deny the request and go without the functionality.") - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.dismiss(); - UserPreference.saveLocationPermDiag(context); - if (ContextCompat.checkSelfPermission(context, - Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, - COARSE_LOCATION_REQUEST); - } + .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> { + dialogInterface.dismiss(); + UserPreference.saveLocationPermDiag(context); + if (ContextCompat.checkSelfPermission(context, + Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, + COARSE_LOCATION_REQUEST); } }) .setIcon(android.R.drawable.ic_dialog_alert).show().setCanceledOnTouchOutside(false); @@ -181,22 +178,13 @@ public void checkDatabase() { "This will download the official OUI list from Wireshark and port list from IANA. " + "Note that you won't be able to resolve any MAC vendors or identify services without this data. " + "You can always perform this from the menu later.") - .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.dismiss(); - ouiTask = new DownloadOuisAsyncTask(db, new OuiParser(), activity); - portTask = new DownloadPortDataAsyncTask(db, new PortParser(), activity); - ouiTask.execute(); - portTask.execute(); - } - }).setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.cancel(); - } - }).setIcon(android.R.drawable.ic_dialog_alert).show().setCanceledOnTouchOutside(false); + .setPositiveButton(android.R.string.yes, (dialogInterface, i) -> { + dialogInterface.dismiss(); + ouiTask = new DownloadOuisAsyncTask(db, new OuiParser(), activity); + portTask = new DownloadPortDataAsyncTask(db, new PortParser(), activity); + ouiTask.execute(); + portTask.execute(); + }).setNegativeButton(android.R.string.no, (dialogInterface, i) -> dialogInterface.cancel()).setIcon(android.R.drawable.ic_dialog_alert).show().setCanceledOnTouchOutside(false); } /** @@ -367,38 +355,18 @@ public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.sortHostname: if (sortAscending) { - hostAdapter.sort(new Comparator() { - @Override - public int compare(Host lhs, Host rhs) { - return rhs.getHostname().toLowerCase().compareTo(lhs.getHostname().toLowerCase()); - } - }); + hostAdapter.sort((lhs, rhs) -> rhs.getHostname().toLowerCase().compareTo(lhs.getHostname().toLowerCase())); } else { - hostAdapter.sort(new Comparator() { - @Override - public int compare(Host lhs, Host rhs) { - return lhs.getHostname().toLowerCase().compareTo(rhs.getHostname().toLowerCase()); - } - }); + hostAdapter.sort((lhs, rhs) -> lhs.getHostname().toLowerCase().compareTo(rhs.getHostname().toLowerCase())); } sortAscending = !sortAscending; return true; case R.id.sortVendor: if (sortAscending) { - hostAdapter.sort(new Comparator() { - @Override - public int compare(Host lhs, Host rhs) { - return rhs.getVendor().toLowerCase().compareTo(lhs.getVendor().toLowerCase()); - } - }); + hostAdapter.sort((lhs, rhs) -> rhs.getVendor().toLowerCase().compareTo(lhs.getVendor().toLowerCase())); } else { - hostAdapter.sort(new Comparator() { - @Override - public int compare(Host lhs, Host rhs) { - return lhs.getVendor().toLowerCase().compareTo(rhs.getVendor().toLowerCase()); - } - }); + hostAdapter.sort((lhs, rhs) -> lhs.getVendor().toLowerCase().compareTo(rhs.getVendor().toLowerCase())); } sortAscending = !sortAscending; @@ -596,7 +564,7 @@ public void onItemClick(AdapterView parent, View view, int position, long id) private void getInternalIp() { try { int netmask = wifi.getInternalWifiSubnet(); - String internalIpWithSubnet = wifi.getInternalWifiIpAddress(String.class) + "/" + Integer.toString(netmask); + String internalIpWithSubnet = wifi.getInternalWifiIpAddress(String.class) + "/" + netmask; internalIp.setText(internalIpWithSubnet); } catch (UnknownHostException | Wireless.NoWifiManagerException e) { Errors.showError(getApplicationContext(), getResources().getString(R.string.notConnectedLan)); @@ -710,31 +678,23 @@ public void onRestoreInstanceState(Bundle savedState) { */ @Override public void processFinish(final Host h, final AtomicInteger i) { - scanHandler.post(new Runnable() { - - @Override - public void run() { - hosts.add(h); - hostAdapter.sort(new Comparator() { - - @Override - public int compare(Host lhs, Host rhs) { - try { - int leftIp = ByteBuffer.wrap(InetAddress.getByName(lhs.getIp()).getAddress()).getInt(); - int rightIp = ByteBuffer.wrap(InetAddress.getByName(rhs.getIp()).getAddress()).getInt(); - - return leftIp - rightIp; - } catch (UnknownHostException ignored) { - return 0; - } - } - }); + scanHandler.post(() -> { + hosts.add(h); + hostAdapter.sort((lhs, rhs) -> { + try { + int leftIp = ByteBuffer.wrap(InetAddress.getByName(lhs.getIp()).getAddress()).getInt(); + int rightIp = ByteBuffer.wrap(InetAddress.getByName(rhs.getIp()).getAddress()).getInt(); - discoverHostsBtn.setText(discoverHostsStr + " (" + hosts.size() + ")"); - if (i.decrementAndGet() == 0) { - discoverHostsBtn.setAlpha(1); - discoverHostsBtn.setEnabled(true); + return leftIp - rightIp; + } catch (UnknownHostException ignored) { + return 0; } + }); + + discoverHostsBtn.setText(discoverHostsStr + " (" + hosts.size() + ")"); + if (i.decrementAndGet() == 0) { + discoverHostsBtn.setAlpha(1); + discoverHostsBtn.setEnabled(true); } }); } @@ -769,13 +729,9 @@ public void processFinish(String output) { */ @Override public void processFinish(final boolean output) { - scanHandler.post(new Runnable() { - - @Override - public void run() { - if (output && scanProgressDialog != null && scanProgressDialog.isShowing()) { - scanProgressDialog.dismiss(); - } + scanHandler.post(() -> { + if (output && scanProgressDialog != null && scanProgressDialog.isShowing()) { + scanProgressDialog.dismiss(); } }); } @@ -788,12 +744,6 @@ public void run() { */ @Override public void processFinish(final T output) { - scanHandler.post(new Runnable() { - - @Override - public void run() { - Errors.showError(getApplicationContext(), output.getLocalizedMessage()); - } - }); + scanHandler.post(() -> Errors.showError(getApplicationContext(), output.getLocalizedMessage())); } } diff --git a/app/src/main/java/com/aaronjwood/portauthority/activity/WanHostActivity.java b/app/src/main/java/com/aaronjwood/portauthority/activity/WanHostActivity.java index accfb974..2565a748 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/activity/WanHostActivity.java +++ b/app/src/main/java/com/aaronjwood/portauthority/activity/WanHostActivity.java @@ -138,13 +138,7 @@ public void processFinish(boolean output) { } if (!output) { - handler.post(new Runnable() { - - @Override - public void run() { - Toast.makeText(getApplicationContext(), "Please enter a valid URL or IP address", Toast.LENGTH_SHORT).show(); - } - }); + handler.post(() -> Toast.makeText(getApplicationContext(), "Please enter a valid URL or IP address", Toast.LENGTH_SHORT).show()); } } } diff --git a/app/src/main/java/com/aaronjwood/portauthority/async/DownloadAsyncTask.java b/app/src/main/java/com/aaronjwood/portauthority/async/DownloadAsyncTask.java index 55433b50..bc2e0c38 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/async/DownloadAsyncTask.java +++ b/app/src/main/java/com/aaronjwood/portauthority/async/DownloadAsyncTask.java @@ -15,6 +15,7 @@ import java.io.InputStreamReader; import java.lang.ref.WeakReference; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.zip.GZIPInputStream; import javax.net.ssl.HttpsURLConnection; @@ -42,12 +43,9 @@ protected void onPreExecute() { dialog = new ProgressDialog(ctx, R.style.DialogTheme); dialog.setMessage(ctx.getResources().getString(R.string.downloadingData)); dialog.setCanceledOnTouchOutside(false); - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialogInterface) { - dialogInterface.cancel(); - cancel(true); - } + dialog.setOnCancelListener(dialogInterface -> { + dialogInterface.cancel(); + cancel(true); }); dialog.show(); } @@ -73,7 +71,7 @@ final void doInBackground(String service, Parser parser) { return; } - in = new BufferedReader(new InputStreamReader(new GZIPInputStream(connection.getInputStream()), "UTF-8")); + in = new BufferedReader(new InputStreamReader(new GZIPInputStream(connection.getInputStream()), StandardCharsets.UTF_8)); String line; while ((line = in.readLine()) != null) { diff --git a/app/src/main/java/com/aaronjwood/portauthority/async/ScanHostsAsyncTask.java b/app/src/main/java/com/aaronjwood/portauthority/async/ScanHostsAsyncTask.java index a348e65b..8412a769 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/async/ScanHostsAsyncTask.java +++ b/app/src/main/java/com/aaronjwood/portauthority/async/ScanHostsAsyncTask.java @@ -18,6 +18,7 @@ import java.lang.ref.WeakReference; import java.net.InetAddress; import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -174,7 +175,7 @@ protected final void onProgressUpdate(Void... params) { } } } else { - reader = new BufferedReader(new InputStreamReader(new FileInputStream(ARP_TABLE), "UTF-8")); + reader = new BufferedReader(new InputStreamReader(new FileInputStream(ARP_TABLE), StandardCharsets.UTF_8)); reader.readLine(); // Skip header. String line; @@ -194,43 +195,39 @@ protected final void onProgressUpdate(Void... params) { for (Pair pair : pairs) { String ip = pair.first; String macAddress = pair.second; - executor.execute(new Runnable() { - - @Override - public void run() { - Host host; - try { - host = new Host(ip, macAddress, db); - } catch (IOException e) { - host = new Host(ip, macAddress); - } + executor.execute(() -> { + Host host; + try { + host = new Host(ip, macAddress, db); + } catch (IOException e) { + host = new Host(ip, macAddress); + } - MainAsyncResponse activity = delegate.get(); - try { - InetAddress add = InetAddress.getByName(ip); - String hostname = add.getCanonicalHostName(); - host.setHostname(hostname); + MainAsyncResponse activity1 = delegate.get(); + try { + InetAddress add = InetAddress.getByName(ip); + String hostname = add.getCanonicalHostName(); + host.setHostname(hostname); - if (activity != null) { - activity.processFinish(host, numHosts); - } - } catch (UnknownHostException e) { - numHosts.decrementAndGet(); - activity.processFinish(e); - return; + if (activity1 != null) { + activity1.processFinish(host, numHosts); } + } catch (UnknownHostException e) { + numHosts.decrementAndGet(); + activity1.processFinish(e); + return; + } - try { - NbtAddress[] netbios = NbtAddress.getAllByAddress(ip); - for (NbtAddress addr : netbios) { - if (addr.getNameType() == NETBIOS_FILE_SERVER) { - host.setHostname(addr.getHostName()); - return; - } + try { + NbtAddress[] netbios = NbtAddress.getAllByAddress(ip); + for (NbtAddress addr : netbios) { + if (addr.getNameType() == NETBIOS_FILE_SERVER) { + host.setHostname(addr.getHostName()); + return; } - } catch (UnknownHostException e) { - // It's common that many discovered hosts won't have a NetBIOS entry. } + } catch (UnknownHostException e) { + // It's common that many discovered hosts won't have a NetBIOS entry. } }); } diff --git a/app/src/main/java/com/aaronjwood/portauthority/runnable/ScanPortsRunnable.java b/app/src/main/java/com/aaronjwood/portauthority/runnable/ScanPortsRunnable.java index c11a507b..e1c52b20 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/runnable/ScanPortsRunnable.java +++ b/app/src/main/java/com/aaronjwood/portauthority/runnable/ScanPortsRunnable.java @@ -13,6 +13,7 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.nio.channels.IllegalBlockingModeException; +import java.nio.charset.StandardCharsets; public class ScanPortsRunnable implements Runnable { private String ip; @@ -65,12 +66,12 @@ public void run() { SparseArray portData = new SparseArray<>(); String data = null; try { - InputStreamReader input = new InputStreamReader(socket.getInputStream(), "UTF-8"); + InputStreamReader input = new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8); BufferedReader buffered = new BufferedReader(input); if (i == 22) { data = parseSSH(buffered); } else if (i == 80 || i == 443 || i == 8080) { - PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true); + PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true); data = parseHTTP(buffered, out); } } catch (IOException e) { From 14a14a8f43c4a697cc50177afeca92fb0021a5fb Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Sun, 23 Feb 2020 20:36:09 -0800 Subject: [PATCH 12/16] Fix DNS lookups --- app/build.gradle | 2 +- app/proguard.pro | 6 ---- .../async/DnsLookupAsyncTask.java | 31 ++++++++++++++++--- .../async/DownloadAsyncTask.java | 1 - 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f8375ead..b30fbf02 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -69,7 +69,7 @@ dependencies { compile 'com.android.support:appcompat-v7:28.0.0' compile 'com.squareup.okhttp3:okhttp:3.10.0' compile 'jcifs:jcifs:1.3.17' - compile 'dnsjava:dnsjava:2.1.7' + compile 'dnsjava:dnsjava:3.0.1' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4' testCompile 'junit:junit:4.12' diff --git a/app/proguard.pro b/app/proguard.pro index 26ef9e2c..0b7eb396 100644 --- a/app/proguard.pro +++ b/app/proguard.pro @@ -1,9 +1,3 @@ --dontnote org.xbill.DNS.spi.DNSJavaNameServiceDescriptor --dontwarn org.xbill.DNS.spi.DNSJavaNameServiceDescriptor --keep class org.xbill.** { *; } --keepattributes EnclosingMethod --keepattributes InnerClasses - -dontwarn okhttp3.** -dontwarn okio.** -dontwarn javax.annotation.** diff --git a/app/src/main/java/com/aaronjwood/portauthority/async/DnsLookupAsyncTask.java b/app/src/main/java/com/aaronjwood/portauthority/async/DnsLookupAsyncTask.java index d853eafa..abf77bb3 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/async/DnsLookupAsyncTask.java +++ b/app/src/main/java/com/aaronjwood/portauthority/async/DnsLookupAsyncTask.java @@ -1,14 +1,21 @@ package com.aaronjwood.portauthority.async; +import android.content.Context; import android.os.AsyncTask; import com.aaronjwood.portauthority.response.DnsAsyncResponse; +import org.xbill.DNS.ExtendedResolver; import org.xbill.DNS.Lookup; import org.xbill.DNS.Record; +import org.xbill.DNS.Resolver; import org.xbill.DNS.TextParseException; +import org.xbill.DNS.config.AndroidResolverConfigProvider; +import org.xbill.DNS.config.InitializationException; import java.lang.ref.WeakReference; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; public class DnsLookupAsyncTask extends AsyncTask { @@ -33,11 +40,23 @@ public DnsLookupAsyncTask(DnsAsyncResponse delegate) { protected String doInBackground(String... params) { String domain = params[0]; int recordType = Integer.parseInt(params[1]); + AndroidResolverConfigProvider resolverCfg = new AndroidResolverConfigProvider(); + Context ctx = (Context) this.delegate.get(); + AndroidResolverConfigProvider.setContext(ctx); Record[] records; - try { - records = new Lookup(domain, recordType).run(); - if (records == null) { + resolverCfg.initialize(); + String[] servers = new String[resolverCfg.servers().size()]; + for (int i = 0; i < resolverCfg.servers().size(); i++) { + InetSocketAddress server = resolverCfg.servers().get(i); + servers[i] = server.getHostName(); + } + + Resolver resolver = new ExtendedResolver(servers); + Lookup lookup = new Lookup(domain, recordType); + lookup.setResolver(resolver); + records = lookup.run(); + if (records == null || records.length == 0) { return "No records found."; } @@ -49,7 +68,11 @@ protected String doInBackground(String... params) { return answer.toString(); } catch (TextParseException e) { - return "Error performing lookup!"; + return "Error performing lookup: " + e.getMessage(); + } catch (InitializationException e) { + return "Error initializing resolver: " + e.getMessage(); + } catch (UnknownHostException e) { + return "Resolver host is unknown:: " + e.getMessage(); } } diff --git a/app/src/main/java/com/aaronjwood/portauthority/async/DownloadAsyncTask.java b/app/src/main/java/com/aaronjwood/portauthority/async/DownloadAsyncTask.java index bc2e0c38..bf8b0369 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/async/DownloadAsyncTask.java +++ b/app/src/main/java/com/aaronjwood/portauthority/async/DownloadAsyncTask.java @@ -2,7 +2,6 @@ import android.app.ProgressDialog; import android.content.Context; -import android.content.DialogInterface; import android.os.AsyncTask; import com.aaronjwood.portauthority.R; From 84e5e77f6bf6dffd06e177c8681277000423b7e0 Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Sun, 23 Feb 2020 20:38:49 -0800 Subject: [PATCH 13/16] Collapse code --- .../com/aaronjwood/portauthority/async/DnsLookupAsyncTask.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/aaronjwood/portauthority/async/DnsLookupAsyncTask.java b/app/src/main/java/com/aaronjwood/portauthority/async/DnsLookupAsyncTask.java index abf77bb3..4713dc08 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/async/DnsLookupAsyncTask.java +++ b/app/src/main/java/com/aaronjwood/portauthority/async/DnsLookupAsyncTask.java @@ -43,7 +43,6 @@ protected String doInBackground(String... params) { AndroidResolverConfigProvider resolverCfg = new AndroidResolverConfigProvider(); Context ctx = (Context) this.delegate.get(); AndroidResolverConfigProvider.setContext(ctx); - Record[] records; try { resolverCfg.initialize(); String[] servers = new String[resolverCfg.servers().size()]; @@ -55,7 +54,7 @@ protected String doInBackground(String... params) { Resolver resolver = new ExtendedResolver(servers); Lookup lookup = new Lookup(domain, recordType); lookup.setResolver(resolver); - records = lookup.run(); + Record[] records = lookup.run(); if (records == null || records.length == 0) { return "No records found."; } From d95bfc2735941d0f19a8efe1a7485ae8a80ad45c Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Sun, 23 Feb 2020 21:07:43 -0800 Subject: [PATCH 14/16] Request extra permissions to be able to get the SSID on Android 10+ --- app/src/main/AndroidManifest.xml | 3 +- .../portauthority/activity/MainActivity.java | 68 +++++++++++++------ .../portauthority/utils/UserPreference.java | 31 +++++++-- 3 files changed, 74 insertions(+), 28 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4b1238f9..142da436 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,7 +5,8 @@ - + + = Build.VERSION_CODES.O) { - if (!UserPreference.getLocationPermDiag(context)) { - Activity activity = this; - new AlertDialog.Builder(activity, R.style.DialogTheme).setTitle("SSID Access") - .setMessage("Android 8+ now requires location permissions to read the SSID. " + - "If this is not something you're comfortable with just deny the request and go without the functionality.") - .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> { - dialogInterface.dismiss(); - UserPreference.saveLocationPermDiag(context); - if (ContextCompat.checkSelfPermission(context, - Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, - COARSE_LOCATION_REQUEST); - } - }) - .setIcon(android.R.drawable.ic_dialog_alert).show().setCanceledOnTouchOutside(false); + if (UserPreference.getCoarseLocationPermDiag(context) || UserPreference.getFineLocationPermDiag(context)) { + return; } - } - intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + Activity activity = this; + String title = "Android 8-9 SSID Access"; + String message = "Android 8-9 requires coarse location permissions to read the SSID. " + + "If this is not something you're comfortable with just deny the request and go without the functionality."; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + title = "Android 10+ SSID Access"; + message = "Android 10+ requires fine location permissions to read the SSID. " + + "If this is not something you're comfortable with just deny the request and go without the functionality."; + } + + new AlertDialog.Builder(activity, R.style.DialogTheme).setTitle(title) + .setMessage(message) + .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> { + dialogInterface.dismiss(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + UserPreference.saveFineLocationPermDiag(context); + } else { + UserPreference.saveCoarseLocationPermDiag(context); + } + + String perm = Manifest.permission.ACCESS_COARSE_LOCATION; + int request = COARSE_LOCATION_REQUEST; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + perm = Manifest.permission.ACCESS_FINE_LOCATION; + request = FINE_LOCATION_REQUEST; + } + + if (ContextCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(activity, new String[]{perm}, request); + } + }) + .setIcon(android.R.drawable.ic_dialog_alert).show().setCanceledOnTouchOutside(false); + } } /** diff --git a/app/src/main/java/com/aaronjwood/portauthority/utils/UserPreference.java b/app/src/main/java/com/aaronjwood/portauthority/utils/UserPreference.java index 44dfdfd8..c1c5f912 100644 --- a/app/src/main/java/com/aaronjwood/portauthority/utils/UserPreference.java +++ b/app/src/main/java/com/aaronjwood/portauthority/utils/UserPreference.java @@ -22,7 +22,8 @@ public class UserPreference { private static final String LAN_SOCKET_TIMEOUT = "lanTimeout"; private static final String WAN_SOCKET_TIMEOUT = "wanTimeout"; private static final String HOST_SOCKET_TIMEOUT = "hostTimeout"; - private static final String LOCATION_PERM_DIAG = "locationPermDiag"; + private static final String COARSE_LOCATION_PERM_DIAG = "COARSE_LOCATION"; + private static final String FINE_LOCATION_PERM_DIAG = "FINE_LOCATION"; /** * Saves the last used host address for later use. @@ -39,19 +40,35 @@ public static void saveLastUsedHostAddress(@NonNull Context context, @Nullable S } /** - * Saves the state of the location permission dialog. + * Saves the state of the coarse location permission dialog. */ - public static void saveLocationPermDiag(@NonNull Context context) { + public static void saveCoarseLocationPermDiag(@NonNull Context context) { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); - preferences.edit().putBoolean(LOCATION_PERM_DIAG, true).apply(); + preferences.edit().putBoolean(COARSE_LOCATION_PERM_DIAG, true).apply(); } /** - * Saves the state of the location permission dialog. + * Saves the state of the fine location permission dialog. */ - public static boolean getLocationPermDiag(@NonNull Context context) { + public static void saveFineLocationPermDiag(@NonNull Context context) { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); - return preferences.getBoolean(LOCATION_PERM_DIAG, false); + preferences.edit().putBoolean(FINE_LOCATION_PERM_DIAG, true).apply(); + } + + /** + * Saves the state of the coarse location permission dialog. + */ + public static boolean getCoarseLocationPermDiag(@NonNull Context context) { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + return preferences.getBoolean(COARSE_LOCATION_PERM_DIAG, false); + } + + /** + * Saves the state of the fine location permission dialog. + */ + public static boolean getFineLocationPermDiag(@NonNull Context context) { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + return preferences.getBoolean(FINE_LOCATION_PERM_DIAG, false); } /** From dba92849c9e65c35bd350e842c02972626881582 Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Sun, 23 Feb 2020 21:14:37 -0800 Subject: [PATCH 15/16] Increase width of side drawer a bit to account for different icon sizes on different devices --- app/src/main/res/layout/activity_main.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index ab340775..179f57f3 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -197,7 +197,7 @@ From 3c4f327c9cdf2d38b4d5c00f0003625abe260af6 Mon Sep 17 00:00:00 2001 From: Aaron Wood Date: Sun, 23 Feb 2020 21:25:50 -0800 Subject: [PATCH 16/16] Bump versions, bump libs, remove old unnecessary code --- app/build.gradle | 22 ++++++------- app/src/main/AndroidManifest.xml | 1 - .../portauthority/PortAuthority.java | 33 ------------------- 3 files changed, 10 insertions(+), 46 deletions(-) delete mode 100644 app/src/main/java/com/aaronjwood/portauthority/PortAuthority.java diff --git a/app/build.gradle b/app/build.gradle index b30fbf02..a1ea44f7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,8 +21,8 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 29 - versionCode 56 - versionName "2.2.10" + versionCode 57 + versionName "2.2.12" applicationId "com.aaronjwood.portauthority" setProperty("archivesBaseName", "PortAuthority-$versionName") } @@ -65,14 +65,12 @@ android { } dependencies { - compile 'com.android.support:support-v4:28.0.0' - compile 'com.android.support:appcompat-v7:28.0.0' - compile 'com.squareup.okhttp3:okhttp:3.10.0' - compile 'jcifs:jcifs:1.3.17' - compile 'dnsjava:dnsjava:3.0.1' - releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' - debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4' - testCompile 'junit:junit:4.12' - testCompile 'org.mockito:mockito-core:1.10.19' - testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' + implementation 'com.android.support:support-v4:28.0.0' + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.squareup.okhttp3:okhttp:4.4.0' + implementation 'jcifs:jcifs:1.3.17' + implementation 'dnsjava:dnsjava:3.0.1' + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.2' + testImplementation 'junit:junit:4.12' + testImplementation 'org.mockito:mockito-core:1.10.19' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 142da436..1dc1ead1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,6 @@