From 282eab5f4f584e24dfe39e2e803e6b09c118ab4d Mon Sep 17 00:00:00 2001 From: Josef Schlehofer Date: Mon, 10 Aug 2026 22:33:52 +0200 Subject: [PATCH 01/11] Modernize the Gradle build Gradle 9 with AGP 9 built-in Kotlin, a version catalog, SDK 37 and the org.librespeed.speedtest application id. Co-Authored-By: Claude Fable 5 --- .gitignore | 1 + Speedtest-Android/app/build.gradle | 24 ------- Speedtest-Android/app/build.gradle.kts | 68 +++++++++++++++++++ Speedtest-Android/build.gradle | 27 -------- Speedtest-Android/build.gradle.kts | 4 ++ Speedtest-Android/gradle.properties | 18 +---- Speedtest-Android/gradle/libs.versions.toml | 30 ++++++++ .../gradle/wrapper/gradle-wrapper.properties | 5 +- Speedtest-Android/settings.gradle | 2 - Speedtest-Android/settings.gradle.kts | 18 +++++ 10 files changed, 127 insertions(+), 70 deletions(-) delete mode 100644 Speedtest-Android/app/build.gradle create mode 100644 Speedtest-Android/app/build.gradle.kts delete mode 100644 Speedtest-Android/build.gradle create mode 100644 Speedtest-Android/build.gradle.kts create mode 100644 Speedtest-Android/gradle/libs.versions.toml delete mode 100644 Speedtest-Android/settings.gradle create mode 100644 Speedtest-Android/settings.gradle.kts diff --git a/.gitignore b/.gitignore index 098af8c..10cb847 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /_PRIVATE .directory +.DS_Store diff --git a/Speedtest-Android/app/build.gradle b/Speedtest-Android/app/build.gradle deleted file mode 100644 index 78bbc7e..0000000 --- a/Speedtest-Android/app/build.gradle +++ /dev/null @@ -1,24 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion 28 - buildToolsVersion "29.0.0" - defaultConfig { - applicationId "your.name.here.speedtest" - minSdkVersion 15 - targetSdkVersion 28 - versionCode 9 - versionName '1.2.3' - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) -} diff --git a/Speedtest-Android/app/build.gradle.kts b/Speedtest-Android/app/build.gradle.kts new file mode 100644 index 0000000..3fc8771 --- /dev/null +++ b/Speedtest-Android/app/build.gradle.kts @@ -0,0 +1,68 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.compose) +} + +android { + namespace = "org.librespeed.speedtest" + compileSdk = 37 + + defaultConfig { + applicationId = "org.librespeed.speedtest" + minSdk = 26 + targetSdk = 36 + versionCode = 10 + versionName = "2.0.0" + } + + signingConfigs { + //populated from the environment in CI; local builds fall back to the debug key + create("release") { + val keystorePath = System.getenv("SIGNING_KEYSTORE") + if (!keystorePath.isNullOrEmpty()) { + storeFile = file(keystorePath) + storePassword = System.getenv("SIGNING_STORE_PASSWORD") + keyAlias = System.getenv("SIGNING_KEY_ALIAS") + keyPassword = System.getenv("SIGNING_KEY_PASSWORD") + } + } + } + + buildTypes { + release { + isMinifyEnabled = true + isShrinkResources = true + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + if (!System.getenv("SIGNING_KEYSTORE").isNullOrEmpty()) { + signingConfig = signingConfigs.getByName("release") + } + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + buildFeatures { + compose = true + buildConfig = true + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.material3.window.size) + implementation(libs.androidx.compose.material.icons.extended) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.lifecycle.runtime.compose) + implementation(libs.androidx.lifecycle.viewmodel.compose) + implementation(libs.androidx.navigation.compose) + implementation(libs.androidx.datastore.preferences) + debugImplementation(libs.androidx.compose.ui.tooling) + testImplementation(libs.junit) +} diff --git a/Speedtest-Android/build.gradle b/Speedtest-Android/build.gradle deleted file mode 100644 index 801467d..0000000 --- a/Speedtest-Android/build.gradle +++ /dev/null @@ -1,27 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - repositories { - google() - jcenter() - - } - dependencies { - classpath 'com.android.tools.build:gradle:4.1.3' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - google() - jcenter() - - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/Speedtest-Android/build.gradle.kts b/Speedtest-Android/build.gradle.kts new file mode 100644 index 0000000..020183f --- /dev/null +++ b/Speedtest-Android/build.gradle.kts @@ -0,0 +1,4 @@ +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.compose) apply false +} diff --git a/Speedtest-Android/gradle.properties b/Speedtest-Android/gradle.properties index 82618ce..96093a6 100644 --- a/Speedtest-Android/gradle.properties +++ b/Speedtest-Android/gradle.properties @@ -1,15 +1,3 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx1536m -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true - - +org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8 +android.useAndroidX=true +org.gradle.caching=true diff --git a/Speedtest-Android/gradle/libs.versions.toml b/Speedtest-Android/gradle/libs.versions.toml new file mode 100644 index 0000000..327ddbc --- /dev/null +++ b/Speedtest-Android/gradle/libs.versions.toml @@ -0,0 +1,30 @@ +[versions] +agp = "9.3.1" +kotlin = "2.4.10" +coreKtx = "1.19.0" +activityCompose = "1.13.0" +composeBom = "2026.06.01" +lifecycle = "2.11.0" +navigationCompose = "2.9.8" +datastore = "1.2.1" + +[libraries] +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended" } +androidx-compose-material3-window-size = { group = "androidx.compose.material3", name = "material3-window-size-class" } +androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" } +androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" } +androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" } +androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastore" } +junit = { group = "junit", name = "junit", version = "4.13.2" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } diff --git a/Speedtest-Android/gradle/wrapper/gradle-wrapper.properties b/Speedtest-Android/gradle/wrapper/gradle-wrapper.properties index 5f38c9b..1e922f4 100644 --- a/Speedtest-Android/gradle/wrapper/gradle-wrapper.properties +++ b/Speedtest-Android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ -#Mon Apr 12 15:03:57 CEST 2021 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip diff --git a/Speedtest-Android/settings.gradle b/Speedtest-Android/settings.gradle deleted file mode 100644 index 33b9b25..0000000 --- a/Speedtest-Android/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -include ':app' -rootProject.name='Speedtest-Android' diff --git a/Speedtest-Android/settings.gradle.kts b/Speedtest-Android/settings.gradle.kts new file mode 100644 index 0000000..3ca903b --- /dev/null +++ b/Speedtest-Android/settings.gradle.kts @@ -0,0 +1,18 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "LibreSpeed" +include(":app") From d1394df63630d6bc6f6c99190eafd7815af366d5 Mon Sep 17 00:00:00 2001 From: Josef Schlehofer Date: Mon, 10 Aug 2026 22:33:53 +0200 Subject: [PATCH 02/11] Fix the engine networking Corrects the malformed User-Agent header, accepts any 2xx response, tracks the IP version, estimates loss from unreturned pings and submits telemetry to the tested server. The server list is fetched with timeouts. Each request goes out in one write and ping reports the full round trip: halving it used to hide the round trip that Nagle's algorithm added to the separate writes. The upload send buffer is left at the socket default; the fixed 16 KB capped every stream at about 32 KB per round trip. The random payload is built once per process. Server selection pings 16 servers at once and stops pinging one that cannot beat the best; Stop closes the IP lookup. Co-Authored-By: Claude Fable 5 --- .../fdossena/speedtest/core/Speedtest.java | 39 +- .../speedtest/core/base/Connection.java | 112 +++- .../core/config/SpeedtestConfig.java | 4 +- .../core/download/DownloadStream.java | 31 +- .../speedtest/core/download/Downloader.java | 13 +- .../fdossena/speedtest/core/getIP/GetIP.java | 29 +- .../speedtest/core/ping/PingStream.java | 47 +- .../fdossena/speedtest/core/ping/Pinger.java | 13 +- .../core/serverSelector/ServerSelector.java | 18 +- .../core/serverSelector/TestPoint.java | 11 + .../speedtest/core/upload/UploadStream.java | 31 +- .../speedtest/core/upload/Uploader.java | 26 +- .../core/worker/SpeedtestWorker.java | 72 ++- .../com/fdossena/speedtest/ui/GaugeView.java | 122 ---- .../fdossena/speedtest/ui/MainActivity.java | 528 ------------------ 15 files changed, 343 insertions(+), 753 deletions(-) delete mode 100644 Speedtest-Android/app/src/main/java/com/fdossena/speedtest/ui/GaugeView.java delete mode 100644 Speedtest-Android/app/src/main/java/com/fdossena/speedtest/ui/MainActivity.java diff --git a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/Speedtest.java b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/Speedtest.java index 03a52c8..360c393 100644 --- a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/Speedtest.java +++ b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/Speedtest.java @@ -5,7 +5,6 @@ import org.json.JSONObject; import java.io.BufferedReader; -import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.ArrayList; @@ -78,11 +77,15 @@ public void addTestPoints(JSONArray json){ } private static class ServerListLoader { + //without timeouts a black-holed network keeps discovery waiting forever + private static final int FETCH_TIMEOUT=5000; private static String read(String url){ + BufferedReader br=null; try{ - URL u=new URL(url); - InputStream in=u.openStream(); - BufferedReader br=new BufferedReader(new InputStreamReader(u.openStream())); + java.net.URLConnection conn=new URL(url).openConnection(); + conn.setConnectTimeout(FETCH_TIMEOUT); + conn.setReadTimeout(FETCH_TIMEOUT); + br=new BufferedReader(new InputStreamReader(conn.getInputStream())); String s=""; try{ for(;;){ @@ -90,11 +93,13 @@ private static String read(String url){ if(r==null) break; else s+=r; } }catch(Throwable t){} - br.close(); - in.close(); return s; }catch(Throwable t){ return null; + }finally{ + if(br!=null){ + try{br.close();}catch(Throwable t){} + } } } @@ -195,15 +200,20 @@ public void onPingJitterUpdate(double ping, double jitter, double progress) { callback.onPingJitterUpdate(ping, jitter, progress); } + @Override + public void onLossUpdate(double loss) { + callback.onLossUpdate(loss); + } + @Override public void onIPInfoUpdate(String ipInfo) { callback.onIPInfoUpdate(ipInfo); } @Override - public void onTestIDReceived(String id) { - String shareURL=prepareShareURL(telemetryConfig); - if(shareURL!=null) shareURL=String.format(shareURL,id); + public void onTestIDReceived(String id, String shareURLTemplate) { + String shareURL=shareURLTemplate; + if(shareURL!=null&&id!=null) shareURL=String.format(shareURL,id); callback.onTestIDReceived(id,shareURL); } @@ -226,16 +236,6 @@ public void onCriticalFailure(String err) { } } - private String prepareShareURL(TelemetryConfig c){ - if(c==null) return null; - String server=c.getServer(), shareURL=c.getShareURL(); - if(server==null||server.isEmpty()||shareURL==null||shareURL.isEmpty()) return null; - if(!server.endsWith("/")) server=server+"/"; - while(shareURL.startsWith("/")) shareURL=shareURL.substring(1); - if(server.startsWith("//")) server="https:"+server; - return server+shareURL; - } - public void abort(){ synchronized (mutex) { if (state == 2) ss.stopASAP(); @@ -251,6 +251,7 @@ public static abstract class SpeedtestHandler{ public abstract void onDownloadUpdate(double dl, double progress); public abstract void onUploadUpdate(double ul, double progress); public abstract void onPingJitterUpdate(double ping, double jitter, double progress); + public abstract void onLossUpdate(double loss); public abstract void onIPInfoUpdate(String ipInfo); public abstract void onTestIDReceived(String id, String shareURL); public abstract void onEnd(); diff --git a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/base/Connection.java b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/base/Connection.java index 6e722e2..86249e5 100644 --- a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/base/Connection.java +++ b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/base/Connection.java @@ -13,15 +13,28 @@ import java.util.Locale; import javax.net.SocketFactory; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; public class Connection { private Socket socket; + + public boolean isIPv6(){ + return socket!=null&&socket.getInetAddress() instanceof java.net.Inet6Address; + } private String host; private int port; + private String basePath=""; private int mode=MODE_NOT_SET; private static final int MODE_NOT_SET=0, MODE_HTTP=1, MODE_HTTPS=2; - private static final String USER_AGENT="Speedtest-Android/1.2.3 (SDK "+Build.VERSION.SDK_INT+"; "+Build.PRODUCT+"; Android "+Build.VERSION.RELEASE+")", + private static String userAgent="LibreSpeed-Android (SDK "+Build.VERSION.SDK_INT+"; "+Build.PRODUCT+"; Android "+Build.VERSION.RELEASE+")"; + + public static void setUserAgent(String ua){ + userAgent=ua; + } + + private static final String LOCALE= Build.VERSION.SDK_INT>=21?Locale.getDefault().toLanguageTag():null; public Connection(String url, int connectTimeout, int soTimeout, int recvBuffer, int sendBuffer){ @@ -33,6 +46,7 @@ public Connection(String url, int connectTimeout, int soTimeout, int recvBuffer, URL u=new URL(url); host=u.getHost(); port=u.getPort(); + basePath=stripTrailingSlashes(u.getPath()); }catch(Throwable t){ throw new IllegalArgumentException("Malformed URL (HTTP)"); } @@ -42,6 +56,7 @@ public Connection(String url, int connectTimeout, int soTimeout, int recvBuffer, URL u=new URL(url); host=u.getHost(); port=u.getPort(); + basePath=stripTrailingSlashes(u.getPath()); }catch(Throwable t){ throw new IllegalArgumentException("Malformed URL (HTTPS)"); } @@ -52,24 +67,39 @@ public Connection(String url, int connectTimeout, int soTimeout, int recvBuffer, URL u=new URL("http:"+url); host=u.getHost(); port=u.getPort(); + basePath=stripTrailingSlashes(u.getPath()); }catch(Throwable t){ throw new IllegalArgumentException("Malformed URL (HTTP/HTTPS)"); } }else{ throw new IllegalArgumentException("Malformed URL (Unknown or unspecified protocol)"); } - try{ - if(mode == MODE_NOT_SET && tryHTTPS){ - SocketFactory factory = SSLSocketFactory.getDefault(); - socket=factory.createSocket(); + if(mode == MODE_NOT_SET && tryHTTPS){ + Socket s=new Socket(); + try{ if(connectTimeout>0){ - socket.connect(new InetSocketAddress(host, port==-1?443:port),connectTimeout); + s.connect(new InetSocketAddress(host, port==-1?443:port),connectTimeout); + s.setSoTimeout(connectTimeout); //bounds the handshake reads too }else{ - socket.connect(new InetSocketAddress(host, port==-1?443:port)); + s.connect(new InetSocketAddress(host, port==-1?443:port)); } + SSLSocketFactory factory=(SSLSocketFactory)SSLSocketFactory.getDefault(); + //wrapping with the hostname sets SNI; endpoint identification makes the + //handshake reject certificates that were not issued for this host + SSLSocket ssl=(SSLSocket)factory.createSocket(s,host,port==-1?443:port,true); + SSLParameters params=ssl.getSSLParameters(); + params.setEndpointIdentificationAlgorithm("HTTPS"); + ssl.setSSLParameters(params); + //the handshake must succeed before HTTPS is committed, otherwise a plain + //HTTP server would pass the TCP connect and block the HTTP fallback below + ssl.startHandshake(); + if(connectTimeout>0) s.setSoTimeout(0); + socket=ssl; mode=MODE_HTTPS; + }catch(Throwable t){ + try{s.close();}catch(Throwable t1){} } - }catch(Throwable t){} + } try{ if(mode == MODE_NOT_SET && tryHTTP){ SocketFactory factory = SocketFactory.getDefault(); @@ -144,17 +174,40 @@ public InputStreamReader getInputStreamReader(){ return isr; } + //RFC 7230 section 5.4: the Host header carries the port unless it is the scheme default + private String hostHeader(){ + if(port!=-1&&port!=(mode==MODE_HTTPS?443:80)) return host+":"+port; + return host; + } + + //endpoint paths from the server list are relative to the server URL's path, if it has one + private String resolvePath(String path){ + if(path.startsWith("/")) return path; + return basePath+"/"+path; + } + + private static String stripTrailingSlashes(String path){ + if(path==null) return ""; + while(path.endsWith("/")) path=path.substring(0,path.length()-1); + return path; + } + public void GET(String path, boolean keepAlive) throws Exception{ try{ - if(!path.startsWith("/")) path="/"+path; + path=resolvePath(path); + //one write per request: with Nagle's algorithm every further small + //write waits for the ACK of the previous one, which added a whole + //round trip to every ping + StringBuilder r=new StringBuilder(); + r.append("GET ").append(path).append(" HTTP/1.1\r\n"); + r.append("Host: ").append(hostHeader()).append("\r\n"); + r.append("User-Agent: ").append(userAgent).append("\r\n"); + r.append("Connection: ").append(keepAlive?"keep-alive":"close").append("\r\n"); + r.append("Accept-Encoding: identity\r\n"); + if(LOCALE!=null) r.append("Accept-Language: ").append(LOCALE).append("\r\n"); + r.append("\r\n"); PrintStream ps=getPrintStream(); - ps.print("GET "+path+" HTTP/1.1\r\n"); - ps.print("Host: "+host+"\r\n"); - ps.print("User-Agent: "+USER_AGENT); - ps.print("Connection: "+(keepAlive?"keep-alive":"close")+"\r\n"); - ps.print("Accept-Encoding: identity\r\n"); - if(LOCALE!=null) ps.print("Accept-Language: "+LOCALE+"\r\n"); - ps.print("\r\n"); + ps.print(r.toString()); ps.flush(); }catch (Throwable t){ throw new Exception("Failed to send GET request"); @@ -163,18 +216,20 @@ public void GET(String path, boolean keepAlive) throws Exception{ public void POST(String path, boolean keepAlive, String contentType, long contentLength) throws Exception{ try{ - if(!path.startsWith("/")) path="/"+path; + path=resolvePath(path); + StringBuilder r=new StringBuilder(); + r.append("POST ").append(path).append(" HTTP/1.1\r\n"); + r.append("Host: ").append(hostHeader()).append("\r\n"); + r.append("User-Agent: ").append(userAgent).append("\r\n"); + r.append("Connection: ").append(keepAlive?"keep-alive":"close").append("\r\n"); + r.append("Accept-Encoding: identity\r\n"); + if(LOCALE!=null) r.append("Accept-Language: ").append(LOCALE).append("\r\n"); + if(contentType!=null) r.append("Content-Type: ").append(contentType).append("\r\n"); + r.append("Content-Encoding: identity\r\n"); + if(contentLength>=0) r.append("Content-Length: ").append(contentLength).append("\r\n"); + r.append("\r\n"); PrintStream ps=getPrintStream(); - ps.print("POST "+path+" HTTP/1.1\r\n"); - ps.print("Host: "+host+"\r\n"); - ps.print("User-Agent: "+USER_AGENT+"\r\n"); - ps.print("Connection: "+(keepAlive?"keep-alive":"close")+"\r\n"); - ps.print("Accept-Encoding: identity\r\n"); - if(LOCALE!=null) ps.print("Accept-Language: "+LOCALE+"\r\n"); - if(contentType!=null) ps.print("Content-Type: "+contentType+"\r\n"); - ps.print("Content-Encoding: identity\r\n"); - if(contentLength>=0) ps.print("Content-Length: "+contentLength+"\r\n"); - ps.print("\r\n"); + ps.print(r.toString()); ps.flush(); }catch (Throwable t){ throw new Exception("Failed to send POST request"); @@ -201,7 +256,8 @@ public HashMap parseResponseHeaders() throws Exception{ try{ HashMap ret=new HashMap<>(); String s=readLineUnbuffered(); - if(!s.contains("200 OK")) throw new Exception("Did not receive an HTTP 200 ("+s.trim()+")"); + String[] statusParts=s.trim().split(" "); + if(statusParts.length<2||!statusParts[1].startsWith("2")) throw new Exception("Did not receive an HTTP 2xx ("+s.trim()+")"); while(true){ s=readLineUnbuffered(); if(s.trim().isEmpty()) break; diff --git a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/config/SpeedtestConfig.java b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/config/SpeedtestConfig.java index c7d7584..e398aab 100644 --- a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/config/SpeedtestConfig.java +++ b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/config/SpeedtestConfig.java @@ -9,7 +9,9 @@ public class SpeedtestConfig { private int dl_streamDelay=300, ul_streamDelay=300; private double dl_graceTime=1.5, ul_graceTime=1.5; private int dl_connectTimeout=5000, dl_soTimeout=10000, ul_connectTimeout=5000, ul_soTimeout=10000, ping_connectTimeout=2000, ping_soTimeout=5000; - private int dl_recvBuffer=-1, dl_sendBuffer=-1, ul_recvBuffer=-1, ul_sendBuffer=16384, ping_recvBuffer=-1, ping_sendBuffer=-1; + //a fixed 16 KB send buffer locked the kernel out of autotuning and capped each + //upload stream at roughly 32 KB per round trip; -1 leaves the socket default + private int dl_recvBuffer=-1, dl_sendBuffer=-1, ul_recvBuffer=-1, ul_sendBuffer=-1, ping_recvBuffer=-1, ping_sendBuffer=-1; private String errorHandlingMode=ONERROR_ATTEMPT_RESTART; public static final String ONERROR_FAIL="fail", ONERROR_ATTEMPT_RESTART="attempt-restart", ONERROR_MUST_RESTART="must-restart"; private int time_dl_max=15, time_ul_max=15; diff --git a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/download/DownloadStream.java b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/download/DownloadStream.java index b4acee5..d011c5e 100644 --- a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/download/DownloadStream.java +++ b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/download/DownloadStream.java @@ -9,11 +9,13 @@ public abstract class DownloadStream { private String server, path; private int ckSize; private int connectTimeout, soTimeout, recvBuffer, sendBuffer; - private Connection c=null; - private Downloader downloader; + private volatile Connection c=null; + private volatile Downloader downloader; private String errorHandlingMode= SpeedtestConfig.ONERROR_ATTEMPT_RESTART; - private long currentDownloaded=0, previouslyDownloaded=0; - private boolean stopASAP=false; + private volatile long currentDownloaded=0, previouslyDownloaded=0; + //ended means no downloader will ever (re)appear: hard failure or stopped + //before one was created; join() must not keep waiting past it + private volatile boolean stopASAP=false, ended=false; private Logger log; public DownloadStream(String server, String path, int ckSize, String errorHandlingMode, int connectTimeout, int soTimeout, int recvBuffer, int sendBuffer, Logger log){ @@ -41,6 +43,7 @@ public void run(){ try { c = new Connection(server, connectTimeout, soTimeout, recvBuffer, sendBuffer); if(stopASAP){ + ended=true; try{c.close();}catch (Throwable t){} return; } @@ -52,8 +55,10 @@ public void onProgress(long downloaded) { @Override public void onError(String err) { + if(stopASAP) return; log("A downloader died"); if(errorHandlingMode.equals(SpeedtestConfig.ONERROR_FAIL)){ + ended=true; DownloadStream.this.onError(err); return; } @@ -70,7 +75,10 @@ public void onError(String err) { if(errorHandlingMode.equals(SpeedtestConfig.ONERROR_MUST_RESTART)){ Utils.sleep(100); init(); - }else onError(t.toString()); + }else{ + ended=true; + onError(t.toString()); + } } } }.start(); @@ -82,6 +90,12 @@ public void onError(String err) { public void stopASAP(){ stopASAP=true; if(downloader !=null) downloader.stopASAP(); + //closing the connection unblocks a thread parked in a read or write, + //making the stop prompt instead of waiting out the socket timeout + Connection conn=c; + if(conn!=null){ + try{conn.close();}catch (Throwable t){} + } } public long getTotalDownloaded(){ @@ -95,8 +109,11 @@ public void resetDownloadCounter(){ } public void join(){ - while(downloader==null) Utils.sleep(0,100); - try{downloader.join();}catch (Throwable t){} + while(downloader==null&&!ended&&!stopASAP) Utils.sleep(1); + Downloader d=downloader; + if(d!=null){ + try{d.join();}catch (Throwable t){} + } } private void log(String s){ diff --git a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/download/Downloader.java b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/download/Downloader.java index a876ac9..502fd1a 100644 --- a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/download/Downloader.java +++ b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/download/Downloader.java @@ -9,8 +9,8 @@ public abstract class Downloader extends Thread{ private Connection c; private String path; private int ckSize; - private boolean stopASAP=false, resetASAP=false; - private long totDownloaded=0; + private volatile boolean stopASAP=false, resetASAP=false; + private volatile long totDownloaded=0; public Downloader(Connection c, String path, int ckSize){ this.c=c; @@ -38,6 +38,9 @@ public void run(){ if(stopASAP) break; int l=in.read(buf); if(stopASAP) break; + //an orderly close from the server would otherwise count -1 into the + //totals and turn this loop into a hot spin that never recovers + if(l<0) throw new Exception("Connection closed unexpectedly"); bytesLeft-=l; if(resetASAP){ totDownloaded=0; @@ -52,7 +55,9 @@ public void run(){ c.close(); }catch(Throwable t){ try{c.close();}catch(Throwable t1){} - onError(t.toString()); + //a stopped stream closes the connection to unblock this thread; + //that is a clean stop, not an error + if(!stopASAP) onError(t.toString()); } } @@ -70,4 +75,4 @@ public void resetDownloadCounter(){ public long getDownloaded() { return resetASAP?0:totDownloaded; } -} \ No newline at end of file +} diff --git a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/getIP/GetIP.java b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/getIP/GetIP.java index 51dd07f..d9310db 100644 --- a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/getIP/GetIP.java +++ b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/getIP/GetIP.java @@ -16,7 +16,7 @@ public GetIP(Connection c, String path, boolean isp, String distance){ this.c=c; this.path=path; this.isp=isp; - if(!(distance==null||distance.equals(SpeedtestConfig.DISTANCE_KM)||distance.equals(SpeedtestConfig.DISTANCE_MILES))) throw new IllegalArgumentException("Distance must be null, mi or km"); + if(!(distance==null||distance.equals(SpeedtestConfig.DISTANCE_NO)||distance.equals(SpeedtestConfig.DISTANCE_KM)||distance.equals(SpeedtestConfig.DISTANCE_MILES))) throw new IllegalArgumentException("Distance must be null, no, mi or km"); this.distance=distance; start(); } @@ -26,7 +26,7 @@ public void run(){ String s=path; if(isp){ s+= Utils.url_sep(s)+"isp=true"; - if(!distance.equals(SpeedtestConfig.DISTANCE_NO)){ + if(distance!=null&&!distance.equals(SpeedtestConfig.DISTANCE_NO)){ s+=Utils.url_sep(s)+"distance="+distance; } } @@ -34,11 +34,19 @@ public void run(){ HashMap h=c.parseResponseHeaders(); BufferedReader br=new BufferedReader(c.getInputStreamReader()); if(h.get("content-length")!=null){ - //standard encoding - char[] buf=new char[Integer.parseInt(h.get("content-length"))]; - br.read(buf); - String data=new String(buf); - onDataReceived(data); + //standard encoding. content-length counts UTF-8 bytes but the shared reader + //(which may have buffered past the headers) yields chars, so read until the + //decoded chars account for the whole body instead of trusting a single read + int bytesExpected=Integer.parseInt(h.get("content-length")); + StringBuilder sb=new StringBuilder(); + int bytesReceived=0; + while(bytesReceived=2&&statusParts[1].startsWith("2")) ok=true; + } if(l.trim().isEmpty()){ if(chunked){c.readLineUnbuffered(); c.readLineUnbuffered();} break; @@ -40,7 +45,9 @@ public void run(){ if(!ok) throw new Exception("Did not get a 200"); t=System.nanoTime()-t; if(stopASAP) break; - if(!onPong(t/2)) break; + //the full request-response time, as the web client and the CLI report it; + //halving it used to cancel out a round trip that Nagle's algorithm added + if(!onPong(t)) break; } c.close(); }catch(Throwable t){ diff --git a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/serverSelector/ServerSelector.java b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/serverSelector/ServerSelector.java index b353fdb..fa4768d 100644 --- a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/serverSelector/ServerSelector.java +++ b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/core/serverSelector/ServerSelector.java @@ -9,13 +9,19 @@ public abstract class ServerSelector { private ArrayList servers=new ArrayList<>(); - private static final int PARALLELISM=6; + private static final int PARALLELISM=16; private TestPoint selectedTestPoint=null; private int state=NOT_STARTED; private static final int NOT_STARTED=0, WORKING=1, DONE=2; private int timeout; private static final int PINGS=3, SLOW_THRESHOLD=500; - private boolean stopASAP=false; + //written under Speedtest's mutex, read from Pinger callback threads that + //never take it: without volatile an aborted selection keeps walking the list + private volatile boolean stopASAP=false; + //lowest ping of any server that has finished; a server whose latest pong + //is already above it cannot win, so its remaining pings are not worth the + //wait -- selection ends when the slow servers have answered once, not thrice + private volatile float bestDone=Float.MAX_VALUE; public ServerSelector(TestPoint[] servers, int timeout){ addTestPoints(servers); @@ -84,13 +90,17 @@ public void onError(String err) { public boolean onPong(long ns) { float p=ns/1000000f; if(tp.ping==-1||p=bestDone) return false; return p0){ + loss=pongsReceived>=expected?0:100.0*(expected-pongsReceived)/expected; + onLossUpdate(loss); + } } private void sendTelemetry(){ if(telemetryConfig.getTelemetryLevel().equals(TelemetryConfig.LEVEL_DISABLED)) return; if(stopASAP&&telemetryConfig.getTelemetryLevel().equals(TelemetryConfig.LEVEL_BASIC)) return; + //the tested server may run its own results backend (this is what the web client uses); + //try it first, then fall back to the centrally configured endpoint + String base=testServerTelemetryBase(); + String localId=submitTelemetry(backend.getServer(),base.isEmpty()?"results/telemetry.php":base+"/results/telemetry.php"); + if(localId!=null){ + onTestIDReceived(localId,shareUrlTemplate(backend.getServer(),base.isEmpty()?"results/?id=%s":base+"/results/?id=%s")); + return; + } + String centralId=submitTelemetry(telemetryConfig.getServer(),telemetryConfig.getPath()); + if(centralId!=null){ + onTestIDReceived(centralId,shareUrlTemplate(telemetryConfig.getServer(),telemetryConfig.getShareURL())); + } + } + + //endpoints usually live in /backend/, the results backend in /results/ + private String testServerTelemetryBase(){ + String pingURL=backend.getPingURL()==null?"":backend.getPingURL(); + int slash=pingURL.lastIndexOf('/'); + String dir=slash==-1?"":pingURL.substring(0,slash); + if(dir.endsWith("backend")) dir=dir.substring(0,dir.length()-"backend".length()); + while(dir.startsWith("/")) dir=dir.substring(1); + while(dir.endsWith("/")) dir=dir.substring(0,dir.length()-1); + return dir; + } + + private String submitTelemetry(String server, String path){ + if(server==null||server.isEmpty()||path==null||path.isEmpty()) return null; try{ - Connection c=new Connection(telemetryConfig.getServer(),-1,-1,-1,-1); - Telemetry t=new Telemetry(c,telemetryConfig.getPath(),telemetryConfig.getTelemetryLevel(),ipIsp,config.getTelemetry_extra(),dl==-1?"":String.format(Locale.ENGLISH,"%.2f",dl),ul==-1?"":String.format(Locale.ENGLISH,"%.2f",ul),ping==-1?"":String.format(Locale.ENGLISH,"%.2f",ping),jitter==-1?"":String.format(Locale.ENGLISH,"%.2f",jitter),log.getLog()) { + Connection c=new Connection(server,-1,-1,-1,-1); + final String[] result=new String[1]; + Telemetry t=new Telemetry(c,path,telemetryConfig.getTelemetryLevel(),ipIsp,config.getTelemetry_extra(),dl==-1?"":String.format(Locale.ENGLISH,"%.2f",dl),ul==-1?"":String.format(Locale.ENGLISH,"%.2f",ul),ping==-1?"":String.format(Locale.ENGLISH,"%.2f",ping),jitter==-1?"":String.format(Locale.ENGLISH,"%.2f",jitter),log.getLog()) { @Override public void onDataReceived(String data) { - if(data.startsWith("id")){ - onTestIDReceived(data.split(" ")[1]); + if(data!=null&&data.startsWith("id")){ + String[] parts=data.split(" "); + if(parts.length>1) result[0]=parts[1]; } } @Override public void onError(String err) { - System.err.println("Telemetry error: "+err); + System.err.println("Telemetry error ("+server+"): "+err); } }; t.join(); + return result[0]; }catch (Throwable t){ - System.err.println("Failed to send telemetry: "+t.toString()); - t.printStackTrace(System.err); + System.err.println("Failed to send telemetry to "+server+": "+t); + return null; } } + private String shareUrlTemplate(String serverBase, String sharePath){ + if(serverBase==null||serverBase.isEmpty()||sharePath==null||sharePath.isEmpty()) return null; + String server=serverBase; + if(!server.endsWith("/")) server=server+"/"; + String path=sharePath; + while(path.startsWith("/")) path=path.substring(1); + if(server.startsWith("//")) server="https:"+server; + return server+path; + } + public void abort(){ if(stopASAP) return; log.l("Manually aborted"); stopASAP=true; + Connection ic=ipConnection; + if(ic!=null){ try{ic.close();}catch(Throwable t){} } } public abstract void onDownloadUpdate(double dl, double progress); public abstract void onUploadUpdate(double ul, double progress); public abstract void onPingJitterUpdate(double ping, double jitter, double progress); + public abstract void onLossUpdate(double loss); public abstract void onIPInfoUpdate(String ipInfo); - public abstract void onTestIDReceived(String id); + public abstract void onTestIDReceived(String id, String shareURLTemplate); public abstract void onEnd(); public abstract void onCriticalFailure(String err); diff --git a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/ui/GaugeView.java b/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/ui/GaugeView.java deleted file mode 100644 index 11a0571..0000000 --- a/Speedtest-Android/app/src/main/java/com/fdossena/speedtest/ui/GaugeView.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.fdossena.speedtest.ui; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.RectF; -import android.util.AttributeSet; -import android.view.View; - -import your.name.here.speedtest.R; - -public class GaugeView extends View { - private float strokeWidth; - private int backgroundColor; - private int fillColor; - private int startAngle; - private int angles; - private int maxValue; - private int value=0; - - public GaugeView(Context context, AttributeSet attrs) { - super(context, attrs); - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GaugeView, 0, 0); - setStrokeWidth(a.getDimension(R.styleable.GaugeView_gauge_strokeWidth, 10)); - setBackgroundColor(a.getColor(R.styleable.GaugeView_gauge_backgroundColor, 0xFFCCCCCC)); - setFillColor(a.getColor(R.styleable.GaugeView_gauge_fillColor, 0xFFFFFFFF)); - setStartAngle(a.getInt(R.styleable.GaugeView_gauge_startAngle, 135)); - setAngles(a.getInt(R.styleable.GaugeView_gauge_angles, 270)); - setMaxValue(a.getInt(R.styleable.GaugeView_gauge_maxValue, 1000)); - } - - public GaugeView(Context context) { - super(context); - } - - private Paint paint=null; - private RectF rect=null; - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - float size = getWidth()16*1024*1024) throw new Exception("Too big"); - options.inJustDecodeBounds = false; - DisplayMetrics displayMetrics = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); - int vh = displayMetrics.heightPixels, vw = displayMetrics.widthPixels; - double desired=Math.max(vw,vh) * 0.7; - double scale=desired/Math.max(iw,ih); - final Bitmap b = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.testbackground, options),(int)(iw*scale), (int)(ih*scale), true); - runOnUiThread(new Runnable() { - @Override - public void run() { - v.setImageBitmap(b); - } - }); - }catch (Throwable t){ - System.err.println("Failed to load testbackground ("+t.getMessage()+")"); - } - page_init(); - } - }.start(); - } - - private static Speedtest st=null; - - private void page_init(){ - new Thread(){ - @Override - public void run() { - runOnUiThread(new Runnable() { - @Override - public void run() { - transition(R.id.page_init,TRANSITION_LENGTH); - } - }); - final TextView t=((TextView)findViewById(R.id.init_text)); - runOnUiThread(new Runnable() { - @Override - public void run() { - t.setText(R.string.init_init); - } - }); - SpeedtestConfig config=null; - TelemetryConfig telemetryConfig=null; - TestPoint[] servers=null; - try{ - String c=readFileFromAssets("SpeedtestConfig.json"); - JSONObject o=new JSONObject(c); - config=new SpeedtestConfig(o); - c=readFileFromAssets("TelemetryConfig.json"); - o=new JSONObject(c); - telemetryConfig=new TelemetryConfig(o); - if(telemetryConfig.getTelemetryLevel().equals(TelemetryConfig.LEVEL_DISABLED)){ - runOnUiThread(new Runnable() { - @Override - public void run() { - hideView(R.id.privacy_open); - } - }); - } - if(st!=null){ - try{st.abort();}catch (Throwable e){} - } - st=new Speedtest(); - st.setSpeedtestConfig(config); - st.setTelemetryConfig(telemetryConfig); - c=readFileFromAssets("ServerList.json"); - if(c.startsWith("\"")||c.startsWith("'")){ //fetch server list from URL - if(!st.loadServerList(c.subSequence(1,c.length()-1).toString())){ - throw new Exception("Failed to load server list"); - } - }else{ //use provided server list - JSONArray a=new JSONArray(c); - if(a.length()==0) throw new Exception("No test points"); - ArrayList s=new ArrayList<>(); - for(int i=0;i availableServers=new ArrayList<>(); - for(TestPoint t:servers) { - if (t.getPing() != -1) availableServers.add(t); - } - int selectedId=availableServers.indexOf(selected); - final Spinner spinner=(Spinner)findViewById(R.id.serverList); - ArrayList options=new ArrayList(); - for(TestPoint t:availableServers){ - options.add(t.getName()); - } - ArrayAdapter adapter=new ArrayAdapter(this,android.R.layout.simple_spinner_dropdown_item,options.toArray(new String[0])); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - spinner.setAdapter(adapter); - spinner.setSelection(selectedId); - final Button b=(Button)findViewById(R.id.start); - b.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - reinitOnResume=false; - page_test(availableServers.get(spinner.getSelectedItemPosition())); - b.setOnClickListener(null); - } - }); - TextView t=(TextView)findViewById(R.id.privacy_open); - t.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - page_privacy(); - } - }); - } - - private void page_privacy(){ - transition(R.id.page_privacy,TRANSITION_LENGTH); - reinitOnResume=false; - ((WebView)findViewById(R.id.privacy_policy)).loadUrl(getString(R.string.privacy_policy)); - TextView t=(TextView)findViewById(R.id.privacy_close); - t.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - transition(R.id.page_serverSelect,TRANSITION_LENGTH); - reinitOnResume=true; - } - }); - } - - private void page_test(final TestPoint selected){ - transition(R.id.page_test,TRANSITION_LENGTH); - st.setSelectedServer(selected); - ((TextView)findViewById(R.id.serverName)).setText(selected.getName()); - ((TextView)findViewById(R.id.dlText)).setText(format(0)); - ((TextView)findViewById(R.id.ulText)).setText(format(0)); - ((TextView)findViewById(R.id.pingText)).setText(format(0)); - ((TextView)findViewById(R.id.jitterText)).setText(format(0)); - ((ProgressBar)findViewById(R.id.dlProgress)).setProgress(0); - ((ProgressBar)findViewById(R.id.ulProgress)).setProgress(0); - ((GaugeView)findViewById(R.id.dlGauge)).setValue(0); - ((GaugeView)findViewById(R.id.ulGauge)).setValue(0); - ((TextView)findViewById(R.id.ipInfo)).setText(""); - ((ImageView)findViewById(R.id.logo_inapp)).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - String url=getString(R.string.logo_inapp_link); - if(url.isEmpty()) return; - Intent i=new Intent(Intent.ACTION_VIEW); - i.setData(Uri.parse(url)); - startActivity(i); - } - }); - final View endTestArea=findViewById(R.id.endTestArea); - final int endTestAreaHeight=endTestArea.getHeight(); - ViewGroup.LayoutParams p=endTestArea.getLayoutParams(); - p.height=0; - endTestArea.setLayoutParams(p); - findViewById(R.id.shareButton).setVisibility(View.GONE); - st.start(new Speedtest.SpeedtestHandler() { - @Override - public void onDownloadUpdate(final double dl, final double progress) { - runOnUiThread(new Runnable() { - @Override - public void run() { - ((TextView)findViewById(R.id.dlText)).setText(progress==0?"...": format(dl)); - ((GaugeView)findViewById(R.id.dlGauge)).setValue(progress==0?0:mbpsToGauge(dl)); - ((ProgressBar)findViewById(R.id.dlProgress)).setProgress((int)(100*progress)); - } - }); - } - - @Override - public void onUploadUpdate(final double ul, final double progress) { - runOnUiThread(new Runnable() { - @Override - public void run() { - ((TextView)findViewById(R.id.ulText)).setText(progress==0?"...": format(ul)); - ((GaugeView)findViewById(R.id.ulGauge)).setValue(progress==0?0:mbpsToGauge(ul)); - ((ProgressBar)findViewById(R.id.ulProgress)).setProgress((int)(100*progress)); - } - }); - - } - - @Override - public void onPingJitterUpdate(final double ping, final double jitter, final double progress) { - runOnUiThread(new Runnable() { - @Override - public void run() { - ((TextView)findViewById(R.id.pingText)).setText(progress==0?"...": format(ping)); - ((TextView)findViewById(R.id.jitterText)).setText(progress==0?"...": format(jitter)); - } - }); - } - - @Override - public void onIPInfoUpdate(final String ipInfo) { - runOnUiThread(new Runnable() { - @Override - public void run() { - ((TextView)findViewById(R.id.ipInfo)).setText(ipInfo); - } - }); - } - - @Override - public void onTestIDReceived(final String id, final String shareURL) { - if(shareURL==null||shareURL.isEmpty()||id==null||id.isEmpty()) return; - runOnUiThread(new Runnable() { - @Override - public void run() { - Button shareButton=(Button)findViewById(R.id.shareButton); - shareButton.setVisibility(View.VISIBLE); - shareButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent share = new Intent(android.content.Intent.ACTION_SEND); - share.setType("text/plain"); - share.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); - share.putExtra(Intent.EXTRA_TEXT, shareURL); - startActivity(Intent.createChooser(share, getString(R.string.test_share))); - } - }); - } - }); - } - - @Override - public void onEnd() { - runOnUiThread(new Runnable() { - @Override - public void run() { - final Button restartButton=(Button)findViewById(R.id.restartButton); - restartButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - page_init(); - restartButton.setOnClickListener(null); - } - }); - } - }); - final long startT=System.currentTimeMillis(), endT=startT+TRANSITION_LENGTH; - new Thread(){ - public void run(){ - while(System.currentTimeMillis()=Build.VERSION_CODES.N) { - l = getResources().getConfiguration().getLocales().get(0); - }else{ - l=getResources().getConfiguration().locale; - } - if(d<10) return String.format(l,"%.2f",d); - if(d<100) return String.format(l,"%.1f",d); - return ""+Math.round(d); - } - - private int mbpsToGauge(double s){ - return (int)(1000*(1-(1/(Math.pow(1.3,Math.sqrt(s)))))); - } - - private String readFileFromAssets(String name) throws Exception{ - BufferedReader b=new BufferedReader(new InputStreamReader(getAssets().open(name))); - String ret=""; - try{ - for(;;){ - String s=b.readLine(); - if(s==null) break; - ret+=s; - } - }catch(EOFException e){} - return ret; - } - - private void hideView(int id){ - View v=findViewById(id); - if(v!=null) v.setVisibility(View.GONE); - } - - private boolean reinitOnResume=false; - @Override - protected void onResume() { - super.onResume(); - if(reinitOnResume){ - reinitOnResume=false; - page_init(); - } - } - - @Override - protected void onDestroy() { - super.onDestroy(); - try{st.abort();}catch (Throwable t){} - } - - @Override - public void onBackPressed() { - if(currentPage==R.id.page_privacy) - transition(R.id.page_serverSelect,TRANSITION_LENGTH); - else super.onBackPressed(); - } - - //PAGE TRANSITION SYSTEM - - private int currentPage=-1; - private boolean transitionBusy=false; //TODO: improve mutex - private int TRANSITION_LENGTH=300; - - private void transition(final int page, final int duration){ - if(transitionBusy){ - new Thread(){ - public void run(){ - try{sleep(10);}catch (Throwable t){} - transition(page,duration); - } - }.start(); - }else transitionBusy=true; - if(page==currentPage) return; - final ViewGroup oldPage=currentPage==-1?null:(ViewGroup)findViewById(currentPage), - newPage=page==-1?null:(ViewGroup)findViewById(page); - new Thread(){ - public void run(){ - long t=System.currentTimeMillis(), endT=t+duration; - runOnUiThread(new Runnable() { - @Override - public void run() { - if(newPage!=null){ - newPage.setAlpha(0); - newPage.setVisibility(View.VISIBLE); - } - if(oldPage!=null){ - oldPage.setAlpha(1); - } - } - }); - while(t Date: Mon, 10 Aug 2026 22:33:53 +0200 Subject: [PATCH 03/11] Rewrite the app in Compose Material 3 Four-tab UI following the design mockups: gauge with live graphs, server management with favorites and distances, history with result and test details, sharing as image, link or text, Czech translation and an adaptive icon. A remembered server is usable as soon as the list is loaded and starting a test during the ping round cancels the round; the share image is rendered off the UI thread. Co-Authored-By: Claude Fable 5 --- .../app/src/main/AndroidManifest.xml | 34 +- .../app/src/main/assets/ServerList.json | 11 +- .../src/main/assets/ServerListFallback.json | 1 + .../org/librespeed/speedtest/MainActivity.kt | 41 ++ .../speedtest/data/AppPreferences.kt | 149 +++++ .../librespeed/speedtest/data/ClientInfo.kt | 13 + .../speedtest/data/CustomServerFactory.kt | 47 ++ .../librespeed/speedtest/data/GeoDistance.kt | 34 ++ .../speedtest/data/HistoryDatabase.kt | 134 +++++ .../librespeed/speedtest/data/NetworkInfo.kt | 50 ++ .../librespeed/speedtest/engine/TestEngine.kt | 98 ++++ .../librespeed/speedtest/share/ShareImage.kt | 187 ++++++ .../librespeed/speedtest/share/ShareResult.kt | 94 +++ .../java/org/librespeed/speedtest/ui/App.kt | 162 ++++++ .../speedtest/ui/components/Sparkline.kt | 51 ++ .../speedtest/ui/components/SpeedGauge.kt | 123 ++++ .../speedtest/ui/history/HistoryScreen.kt | 189 ++++++ .../speedtest/ui/history/HistoryViewModel.kt | 40 ++ .../speedtest/ui/result/ResultScreen.kt | 410 ++++++++++++++ .../speedtest/ui/result/ShareScreen.kt | 173 ++++++ .../speedtest/ui/result/TestDetailsScreen.kt | 184 ++++++ .../speedtest/ui/servers/ServerSheet.kt | 259 +++++++++ .../speedtest/ui/servers/ServersScreen.kt | 357 ++++++++++++ .../speedtest/ui/settings/SettingsScreen.kt | 335 +++++++++++ .../speedtest/ui/speedtest/SpeedtestScreen.kt | 392 +++++++++++++ .../ui/speedtest/SpeedtestViewModel.kt | 357 ++++++++++++ .../librespeed/speedtest/ui/theme/Theme.kt | 94 +++ .../app/src/main/res/drawable/ic_launcher.png | Bin 20326 -> 0 bytes .../res/drawable/ic_launcher_foreground.xml | 52 ++ .../app/src/main/res/drawable/ic_logo.xml | 52 ++ .../app/src/main/res/drawable/logo.png | Bin 37296 -> 0 bytes .../app/src/main/res/drawable/logo_inapp.png | Bin 37343 -> 0 bytes .../src/main/res/drawable/testbackground.png | Bin 278762 -> 0 bytes .../app/src/main/res/layout/activity_main.xml | 536 ------------------ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../app/src/main/res/values-cs/strings.xml | 148 +++++ .../app/src/main/res/values-v21/styles.xml | 15 - .../app/src/main/res/values/attrs.xml | 11 - .../app/src/main/res/values/colors.xml | 25 +- .../app/src/main/res/values/dimens.xml | 42 -- .../app/src/main/res/values/strings.xml | 164 +++++- .../app/src/main/res/values/styles.xml | 15 - .../app/src/main/res/values/themes.xml | 3 + .../app/src/main/res/xml/file_paths.xml | 4 + 44 files changed, 4405 insertions(+), 686 deletions(-) create mode 100644 Speedtest-Android/app/src/main/assets/ServerListFallback.json create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/MainActivity.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/AppPreferences.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/ClientInfo.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/CustomServerFactory.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/GeoDistance.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/HistoryDatabase.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/NetworkInfo.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/engine/TestEngine.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/share/ShareImage.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/share/ShareResult.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/App.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/components/Sparkline.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/components/SpeedGauge.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/history/HistoryScreen.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/history/HistoryViewModel.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/result/ResultScreen.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/result/ShareScreen.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/result/TestDetailsScreen.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/servers/ServerSheet.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/servers/ServersScreen.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/settings/SettingsScreen.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/speedtest/SpeedtestScreen.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/speedtest/SpeedtestViewModel.kt create mode 100644 Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/theme/Theme.kt delete mode 100644 Speedtest-Android/app/src/main/res/drawable/ic_launcher.png create mode 100644 Speedtest-Android/app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 Speedtest-Android/app/src/main/res/drawable/ic_logo.xml delete mode 100644 Speedtest-Android/app/src/main/res/drawable/logo.png delete mode 100644 Speedtest-Android/app/src/main/res/drawable/logo_inapp.png delete mode 100644 Speedtest-Android/app/src/main/res/drawable/testbackground.png delete mode 100644 Speedtest-Android/app/src/main/res/layout/activity_main.xml create mode 100644 Speedtest-Android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 Speedtest-Android/app/src/main/res/values-cs/strings.xml delete mode 100644 Speedtest-Android/app/src/main/res/values-v21/styles.xml delete mode 100644 Speedtest-Android/app/src/main/res/values/attrs.xml delete mode 100644 Speedtest-Android/app/src/main/res/values/dimens.xml delete mode 100644 Speedtest-Android/app/src/main/res/values/styles.xml create mode 100644 Speedtest-Android/app/src/main/res/values/themes.xml create mode 100644 Speedtest-Android/app/src/main/res/xml/file_paths.xml diff --git a/Speedtest-Android/app/src/main/AndroidManifest.xml b/Speedtest-Android/app/src/main/AndroidManifest.xml index 685d61d..8416062 100644 --- a/Speedtest-Android/app/src/main/AndroidManifest.xml +++ b/Speedtest-Android/app/src/main/AndroidManifest.xml @@ -1,19 +1,31 @@ - + + + + + + + android:theme="@style/Theme.LibreSpeed"> + + + + + android:name=".MainActivity" + android:exported="true" + android:launchMode="singleTop"> @@ -21,6 +33,4 @@ - - - \ No newline at end of file + diff --git a/Speedtest-Android/app/src/main/assets/ServerList.json b/Speedtest-Android/app/src/main/assets/ServerList.json index 7719f0f..38317ea 100644 --- a/Speedtest-Android/app/src/main/assets/ServerList.json +++ b/Speedtest-Android/app/src/main/assets/ServerList.json @@ -1,10 +1 @@ -[ - { - "name":"Helsinki, Finland", - "server":"//fi.openspeed.org", - "dlURL":"garbage.php", - "ulURL":"empty.php", - "pingURL":"empty.php", - "getIpURL":"getIP.php" - } -] +"//librespeed.org/backend-servers/servers.php" \ No newline at end of file diff --git a/Speedtest-Android/app/src/main/assets/ServerListFallback.json b/Speedtest-Android/app/src/main/assets/ServerListFallback.json new file mode 100644 index 0000000..f2a4cc1 --- /dev/null +++ b/Speedtest-Android/app/src/main/assets/ServerListFallback.json @@ -0,0 +1 @@ +[{"name":"Amsterdam, Netherlands (Clouvider)","server":"https:\/\/ams.speedtest.clouvider.net\/backend","id":51,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Clouvider","sponsorURL":"https:\/\/www.clouvider.co.uk\/"},{"name":"Amsterdam, Netherlands (Sharktech)","server":"https:\/\/amsspeed.sharktech.net","id":94,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"Sharktech","sponsorURL":"https:\/\/sharktech.net"},{"name":"Argalasti, Magnesia, Greece (Cosmote)","server":"https:\/\/argalasti.skoultsos.eu\/","id":104,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"skoultsos.eu","sponsorURL":"https:\/\/skoultsos.eu"},{"name":"Atlanta, United States (Clouvider)","server":"https:\/\/atl.speedtest.clouvider.net\/backend","id":53,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Clouvider","sponsorURL":"https:\/\/www.clouvider.co.uk\/"},{"name":"Bangalore, India (DigitalOcean)","server":"https:\/\/in1.backend.librespeed.org\/","id":75,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"DigitalOcean","sponsorURL":"https:\/\/www.digitalocean.com"},{"name":"Bari, Italy (GARR)","server":"https:\/\/st-be-ba1.infra.garr.it","id":33,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Consortium GARR","sponsorURL":"https:\/\/garr.it"},{"name":"Belgrade, Serbia (SOX)","server":"https:\/\/speedtest1.sox.rs\/librespeed\/","id":106,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"Serbian Open eXchange","sponsorURL":"https:\/\/sox.rs"},{"name":"Bologna, Italy (GARR)","server":"https:\/\/st-be-bo1.infra.garr.it","id":34,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Consortium GARR","sponsorURL":"https:\/\/garr.it"},{"name":"Bucharest, Romania (ByteShield)","server":"https:\/\/speedtest.byteshield.ro:6060\/","id":98,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"ByteShield Hosting SRL","sponsorURL":"NULL"},{"name":"Chicago, USA (Sharktech)","server":"https:\/\/chispeed.sharktech.net","id":93,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"Sharktech","sponsorURL":"https:\/\/sharktech.net"},{"name":"Denver, USA (Sharktech)","server":"https:\/\/denspeed.sharktech.net","id":92,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"Sharktech","sponsorURL":"https:\/\/sharktech.net"},{"name":"Frankfurt, Germany (Clouvider)","server":"https:\/\/fra.speedtest.clouvider.net\/backend","id":50,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Clouvider","sponsorURL":"https:\/\/www.clouvider.co.uk\/"},{"name":"Frankfurt, Germany (FRA01)","server":"https:\/\/speedtest.lumischvps.cloud\/","id":86,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"LumischVPS","sponsorURL":"https:\/\/discord.gg\/GxYzPwJmA2"},{"name":"Frankfurt, Germany (FS IT-Systeme GmbH)","server":"https:\/\/speed.fs-it.systems\/","id":105,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"FS IT-Systeme GmbH","sponsorURL":"https:\/\/go.bytevault.systems\/fsit-web-spd1"},{"name":"Ghom, Iran (Amin IDC)","server":"https:\/\/fastme.ir\/","id":77,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"Bardia Moshiri","sponsorURL":"https:\/\/bardia.tech\/"},{"name":"Grand Rapids, Michigan (RackGenius)","server":"https:\/\/mispeed.rackgenius.com\/","id":100,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"RackGenius","sponsorURL":"https:\/\/rackgenius.com\/"},{"name":"Helsinki, Finland (3) (Hetzner)","server":"https:\/\/finew.openspeed.org\/","id":22,"dlURL":"backend437\/garbage.php","ulURL":"backend437\/empty.php","pingURL":"backend437\/empty.php","getIpURL":"backend437\/getIP.php","sponsorName":"Daily Health Insurance Group","sponsorURL":"https:\/\/dhig.net\/"},{"name":"Helsinki, Finland (5) (Hetzner)","server":"https:\/\/fast.kabi.tk\/","id":24,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"KABI.tk","sponsorURL":"https:\/\/kabi.tk"},{"name":"Helsinki, Finland (Hetzner)","server":"https:\/\/www.librespeed.fi\/","id":101,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"Pekka Jalonen","sponsorURL":"https:\/\/jalonen.net\/"},{"name":"Johannesburg, South Africa (Host Africa)","server":"https:\/\/za1.backend.librespeed.org\/","id":70,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"HOSTAFRICA","sponsorURL":"https:\/\/www.hostafrica.co.za"},{"name":"Las Vegas, USA (Sharktech)","server":"https:\/\/lasspeed.sharktech.net","id":90,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"Sharktech","sponsorURL":"https:\/\/sharktech.net"},{"name":"London, England (Clouvider)","server":"https:\/\/lon.speedtest.clouvider.net\/backend","id":49,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Clouvider","sponsorURL":"https:\/\/www.clouvider.co.uk\/"},{"name":"Los Angeles, United States (1) (Clouvider)","server":"https:\/\/la.speedtest.clouvider.net\/backend","id":54,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Clouvider","sponsorURL":"https:\/\/www.clouvider.co.uk\/"},{"name":"Los Angeles, USA (Sharktech)","server":"https:\/\/laxspeed.sharktech.net","id":91,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"Sharktech","sponsorURL":"https:\/\/sharktech.net"},{"name":"New York, United States (2) (Clouvider)","server":"https:\/\/nyc.speedtest.clouvider.net\/backend","id":52,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Clouvider","sponsorURL":"https:\/\/www.clouvider.co.uk\/"},{"name":"Nottingham, England (LayerIP)","server":"https:\/\/uk1.backend.librespeed.org","id":43,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"fosshost.org","sponsorURL":"https:\/\/fosshost.org"},{"name":"Novi Sad, Vojvodina, Serbia (E-CAPS.net)","server":"https:\/\/speed1.e-caps.net","id":103,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"E-CAPS.net","sponsorURL":"https:\/\/e-caps.net"},{"name":"Nuremberg, Germany (1) (Hetzner)","server":"https:\/\/de1.backend.librespeed.org","id":28,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Snopyta","sponsorURL":"https:\/\/snopyta.org"},{"name":"Nuremberg, Germany (2) (Hetzner)","server":"https:\/\/de4.backend.librespeed.org","id":27,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"LibreSpeed","sponsorURL":"https:\/\/librespeed.org"},{"name":"Nuremberg, Germany (3) (Hetzner)","server":"https:\/\/de3.backend.librespeed.org","id":30,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"LibreSpeed","sponsorURL":"https:\/\/librespeed.org"},{"name":"Nuremberg, Germany (4) (Hetzner)","server":"https:\/\/de5.backend.librespeed.org","id":31,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"LibreSpeed","sponsorURL":"https:\/\/librespeed.org"},{"name":"Nuremberg, Germany (6) (Hetzner)","server":"https:\/\/librespeed.lukas-heinrich.com\/","id":46,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"luki9100","sponsorURL":"https:\/\/lukas-heinrich.com\/"},{"name":"Ohio, USA (Rust backend)","server":"https:\/\/librespeed-rs.ir\/","id":95,"dlURL":"backend\/garbage","ulURL":"backend\/empty","pingURL":"backend\/empty","getIpURL":"backend\/getIP","sponsorName":"Sudo Dios","sponsorURL":"https:\/\/github.com\/SudoDios"},{"name":"Poznan, Poland (INEA)","server":"https:\/\/speedtest.kamilszczepanski.com","id":74,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Kamil Szczepa?ski","sponsorURL":"https:\/\/kamilszczepanski.com"},{"name":"Prague, Czech Republic (CESNET)","server":"https:\/\/speedtest.cesnet.cz","id":79,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"CESNET","sponsorURL":"https:\/\/www.cesnet.cz"},{"name":"Prague, Czech Republic (Turris)","server":"https:\/\/librespeed.turris.cz","id":85,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"Turris","sponsorURL":"https:\/\/www.turris.com"},{"name":"Roma, Italy (GARR)","server":"https:\/\/st-be-rm2.infra.garr.it","id":35,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Consortium GARR","sponsorURL":"https:\/\/garr.it"},{"name":"Serbia (SOX)","server":"https:\/\/speedtest2.sox.rs","id":87,"dlURL":"libre\/backend\/garbage.php","ulURL":"libre\/backend\/empty.php","pingURL":"libre\/backend\/empty.php","getIpURL":"libre\/backend\/getIP.php","sponsorName":"Serbian Open eXchange (SOX)","sponsorURL":"https:\/\/sox.rs"},{"name":"Singapore (Salvatore Cahyo)","server":"https:\/\/speedtest.dsgroupmedia.com","id":68,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"Salvatore Cahyo","sponsorURL":"https:\/\/salvatorecahyo.my.id"},{"name":"Tehran, Iran (Fanava)","server":"https:\/\/speedme.ir\/","id":76,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"Bardia Moshiri","sponsorURL":"https:\/\/bardia.tech"},{"name":"Tehran, Iran (Faraso)","server":"https:\/\/st.bardia.tech","id":80,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"Bardia Moshiri","sponsorURL":"https:\/\/bardia.tech\/"},{"name":"Tokyo, Japan (A573)","server":"https:\/\/librespeed.a573.net\/","id":82,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"A573","sponsorURL":"https:\/\/mirror.a573.net\/"},{"name":"Vilnius, Lithuania (RackRay)","server":"https:\/\/lt1.backend.librespeed.org\/","id":69,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Time4VPS","sponsorURL":"https:\/\/www.time4vps.com"},{"name":"Virginia, United States, OVH","server":"https:\/\/speed.riverside.rocks\/","id":78,"dlURL":"garbage.php","ulURL":"empty.php","pingURL":"empty.php","getIpURL":"getIP.php","sponsorName":"Riverside Rocks","sponsorURL":"https:\/\/riverside.rocks"},{"name":"Volzhsky, Russia (PowerNet)","server":"https:\/\/speedtest.powernet.com.ru\/","id":102,"dlURL":"backend\/garbage.php","ulURL":"backend\/empty.php","pingURL":"backend\/empty.php","getIpURL":"backend\/getIP.php","sponsorName":"PowerNet","sponsorURL":"powernet.com.ru\/"}] \ No newline at end of file diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/MainActivity.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/MainActivity.kt new file mode 100644 index 0000000..1014db3 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/MainActivity.kt @@ -0,0 +1,41 @@ +package org.librespeed.speedtest + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi +import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.librespeed.speedtest.data.AppPreferences +import org.librespeed.speedtest.data.ClientInfo +import org.librespeed.speedtest.ui.App +import org.librespeed.speedtest.ui.theme.LibreSpeedTheme +import org.librespeed.speedtest.ui.theme.ThemeMode + +class MainActivity : ComponentActivity() { + + @OptIn(ExperimentalMaterial3WindowSizeClassApi::class, androidx.compose.material3.ExperimentalMaterial3Api::class) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + com.fdossena.speedtest.core.base.Connection.setUserAgent(ClientInfo.userAgent) + enableEdgeToEdge() + setContent { + val prefs = remember { AppPreferences(applicationContext) } + val themeMode by prefs.themeMode.collectAsStateWithLifecycle(initialValue = "system") + val windowSizeClass = calculateWindowSizeClass(this) + LibreSpeedTheme( + mode = when (themeMode) { + "light" -> ThemeMode.LIGHT + "dark" -> ThemeMode.DARK + else -> ThemeMode.SYSTEM + } + ) { + App(windowWidth = windowSizeClass.widthSizeClass) + } + } + } + +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/AppPreferences.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/AppPreferences.kt new file mode 100644 index 0000000..15fd715 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/AppPreferences.kt @@ -0,0 +1,149 @@ +package org.librespeed.speedtest.data + +import android.content.Context +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import androidx.datastore.preferences.core.stringSetPreferencesKey +import androidx.datastore.preferences.preferencesDataStore +import com.fdossena.speedtest.core.serverSelector.TestPoint +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map +import org.json.JSONArray +import org.json.JSONObject + +private val Context.dataStore by preferencesDataStore(name = "settings") + +//the public list carries a stable id; custom servers fall back to name+server +fun TestPoint.key(): String = if (serverId > 0) "id:$serverId" else "${name}|${server}" + +class AppPreferences(private val context: Context) { + + private object Keys { + val FAVORITES = stringSetPreferencesKey("favorite_servers") + val CUSTOM_SERVERS = stringPreferencesKey("custom_servers") + val REMEMBERED_SERVER = stringPreferencesKey("remembered_server") + val THEME_MODE = stringPreferencesKey("theme_mode") + val USE_MBYTES = booleanPreferencesKey("use_mbytes") + val TELEMETRY = booleanPreferencesKey("telemetry_enabled") + val SINGLE_CONNECTION = booleanPreferencesKey("single_connection") + val GEO_CACHE = stringPreferencesKey("geo_cache") + } + + suspend fun getGeoCache(): Map> = try { + val json = JSONObject(context.dataStore.data.first()[Keys.GEO_CACHE] ?: "{}") + json.keys().asSequence().mapNotNull { name -> + val parts = json.getString(name).split(",") + parts.takeIf { it.size == 2 }?.let { name to (it[0].toDouble() to it[1].toDouble()) } + }.toMap() + } catch (_: Exception) { + emptyMap() + } + + suspend fun putGeoCache(name: String, lat: Double, lon: Double) { + context.dataStore.edit { preferences -> + val json = try { + JSONObject(preferences[Keys.GEO_CACHE] ?: "{}") + } catch (_: Exception) { + JSONObject() + } + json.put(name, "$lat,$lon") + preferences[Keys.GEO_CACHE] = json.toString() + } + } + + val themeMode: Flow = + context.dataStore.data.map { it[Keys.THEME_MODE] ?: "system" } + + val useMBytes: Flow = + context.dataStore.data.map { it[Keys.USE_MBYTES] ?: false } + + val telemetryEnabled: Flow = + context.dataStore.data.map { it[Keys.TELEMETRY] ?: false } + + val singleConnection: Flow = + context.dataStore.data.map { it[Keys.SINGLE_CONNECTION] ?: false } + + suspend fun setSingleConnection(value: Boolean) { + context.dataStore.edit { it[Keys.SINGLE_CONNECTION] = value } + } + + suspend fun setThemeMode(mode: String) { + context.dataStore.edit { it[Keys.THEME_MODE] = mode } + } + + suspend fun setUseMBytes(value: Boolean) { + context.dataStore.edit { it[Keys.USE_MBYTES] = value } + } + + suspend fun setTelemetryEnabled(value: Boolean) { + context.dataStore.edit { it[Keys.TELEMETRY] = value } + } + + val favorites: Flow> = + context.dataStore.data.map { it[Keys.FAVORITES] ?: emptySet() } + + val rememberedServer: Flow = + context.dataStore.data.map { it[Keys.REMEMBERED_SERVER] } + + val customServers: Flow> = + context.dataStore.data.map { preferences -> + parseCustomServers(preferences[Keys.CUSTOM_SERVERS] ?: "[]") + } + + suspend fun toggleFavorite(key: String) { + context.dataStore.edit { preferences -> + val current = preferences[Keys.FAVORITES] ?: emptySet() + preferences[Keys.FAVORITES] = if (key in current) current - key else current + key + } + } + + suspend fun setRememberedServer(key: String?) { + context.dataStore.edit { preferences -> + if (key == null) preferences.remove(Keys.REMEMBERED_SERVER) + else preferences[Keys.REMEMBERED_SERVER] = key + } + } + + suspend fun addCustomServer(testPoint: TestPoint) { + context.dataStore.edit { preferences -> + val list = parseCustomServers(preferences[Keys.CUSTOM_SERVERS] ?: "[]") + if (list.any { it.key() == testPoint.key() }) return@edit + val array = JSONArray() + (list + testPoint).forEach { array.put(it.toJson()) } + preferences[Keys.CUSTOM_SERVERS] = array.toString() + } + } + + suspend fun removeCustomServer(key: String) { + context.dataStore.edit { preferences -> + val list = parseCustomServers(preferences[Keys.CUSTOM_SERVERS] ?: "[]") + val array = JSONArray() + list.filter { it.key() != key }.forEach { array.put(it.toJson()) } + preferences[Keys.CUSTOM_SERVERS] = array.toString() + } + } + + private fun parseCustomServers(json: String): List = try { + val array = JSONArray(json) + (0 until array.length()).mapNotNull { index -> + try { + TestPoint(array.getJSONObject(index)) + } catch (_: Exception) { + null + } + } + } catch (_: Exception) { + emptyList() + } + + private fun TestPoint.toJson(): JSONObject = JSONObject() + .put("name", name) + .put("server", server) + .put("dlURL", dlURL) + .put("ulURL", ulURL) + .put("pingURL", pingURL) + .put("getIpURL", getIpURL) + +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/ClientInfo.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/ClientInfo.kt new file mode 100644 index 0000000..275d181 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/ClientInfo.kt @@ -0,0 +1,13 @@ +package org.librespeed.speedtest.data + +import android.os.Build +import org.librespeed.speedtest.BuildConfig + +object ClientInfo { + + val client: String = "LibreSpeed Android ${BuildConfig.VERSION_NAME}" + + val userAgent: String = + "LibreSpeed-Android/${BuildConfig.VERSION_NAME} (SDK ${Build.VERSION.SDK_INT}; Android ${Build.VERSION.RELEASE})" + +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/CustomServerFactory.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/CustomServerFactory.kt new file mode 100644 index 0000000..d5a928f --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/CustomServerFactory.kt @@ -0,0 +1,47 @@ +package org.librespeed.speedtest.data + +import com.fdossena.speedtest.core.serverSelector.TestPoint +import java.net.URI + +object CustomServerFactory { + + /** + * Builds a TestPoint from a user supplied URL. The engine only uses host:port of "server", + * so any sub-path has to move into the endpoint fields. Without a scheme the engine tries + * HTTPS first and falls back to HTTP ("//host"). + */ + @Throws(IllegalArgumentException::class) + fun create(name: String, url: String): TestPoint { + require(name.isNotBlank()) { "Name cannot be empty" } + val trimmed = url.trim().trimEnd('/') + val uri = try { + URI(if (trimmed.contains("://")) trimmed else "https://$trimmed") + } catch (e: Exception) { + throw IllegalArgumentException("Invalid URL", e) + } + val host = uri.host ?: throw IllegalArgumentException("Invalid URL") + //IPv6 literals must stay bracketed inside the URL + val bracketedHost = if (host.contains(":") && !host.startsWith("[")) "[$host]" else host + val scheme = when { + trimmed.startsWith("http://") -> "http://" + trimmed.startsWith("https://") -> "https://" + else -> "//" + } + val server = buildString { + append(scheme) + append(bracketedHost) + if (uri.port != -1) append(":${uri.port}") + } + val basePath = uri.path.trim('/') + fun endpoint(file: String) = if (basePath.isEmpty()) file else "$basePath/$file" + return TestPoint( + name.trim(), + server, + endpoint("garbage.php"), + endpoint("empty.php"), + endpoint("empty.php"), + endpoint("getIP.php") + ) + } + +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/GeoDistance.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/GeoDistance.kt new file mode 100644 index 0000000..842e40a --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/GeoDistance.kt @@ -0,0 +1,34 @@ +package org.librespeed.speedtest.data + +import kotlin.math.asin +import kotlin.math.cos +import kotlin.math.pow +import kotlin.math.sin +import kotlin.math.sqrt + +object GeoDistance { + + fun km(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Double { + val earthRadiusKm = 6371.0 + val dLat = Math.toRadians(lat2 - lat1) + val dLon = Math.toRadians(lon2 - lon1) + val a = sin(dLat / 2).pow(2) + + cos(Math.toRadians(lat1)) * cos(Math.toRadians(lat2)) * sin(dLon / 2).pow(2) + return 2 * earthRadiusKm * asin(sqrt(a)) + } + + /** "Prague, Czech Republic (CESNET)" -> "Prague, Czech Republic" */ + fun cleanName(name: String): String = name.substringBefore("(").trim().trimEnd(',') + + /** "Prague, Czech Republic (CESNET)" -> "CESNET" or null */ + fun sponsor(name: String): String? = + name.substringAfter("(", "").removeSuffix(")").trim().ifEmpty { null } + + /** "https://librespeed.org/backend/" -> "librespeed.org/backend" */ + fun hostLabel(url: String): String = url + .removePrefix("https://") + .removePrefix("http://") + .removePrefix("//") + .trimEnd('/') + +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/HistoryDatabase.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/HistoryDatabase.kt new file mode 100644 index 0000000..5d210e4 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/HistoryDatabase.kt @@ -0,0 +1,134 @@ +package org.librespeed.speedtest.data + +import android.content.ContentValues +import android.content.Context +import android.database.sqlite.SQLiteDatabase +import android.database.sqlite.SQLiteOpenHelper +import org.json.JSONArray + +data class HistoryEntry( + val id: Long = 0, + val date: Long, + val server: String, + val ping: Double, + val jitter: Double, + val download: Double, + val upload: Double, + val loss: Double, + val ipInfo: String?, + val ipVersion: Int, + val shareUrl: String?, + val networkType: String? = null, + val downloadSamples: List = emptyList(), + val uploadSamples: List = emptyList(), + val durationMs: Long = 0 +) + +class HistoryDatabase(context: Context) : SQLiteOpenHelper(context, "history.db", null, 3) { + + override fun onCreate(db: SQLiteDatabase) { + db.execSQL( + "CREATE TABLE history (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT," + + "date INTEGER NOT NULL," + + "server TEXT NOT NULL," + + "ping REAL NOT NULL," + + "jitter REAL NOT NULL," + + "download REAL NOT NULL," + + "upload REAL NOT NULL," + + "loss REAL NOT NULL," + + "ipInfo TEXT," + + "ipVersion INTEGER NOT NULL DEFAULT 0," + + "shareUrl TEXT," + + "networkType TEXT," + + "dlSamples TEXT," + + "ulSamples TEXT," + + "duration INTEGER NOT NULL DEFAULT 0)" + ) + } + + override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + if (oldVersion < 2) { + db.execSQL("ALTER TABLE history ADD COLUMN networkType TEXT") + db.execSQL("ALTER TABLE history ADD COLUMN dlSamples TEXT") + db.execSQL("ALTER TABLE history ADD COLUMN ulSamples TEXT") + } + if (oldVersion < 3) { + db.execSQL("ALTER TABLE history ADD COLUMN duration INTEGER NOT NULL DEFAULT 0") + } + } + + fun insert(entry: HistoryEntry): Long = writableDatabase.insert( + "history", null, + ContentValues().apply { + put("date", entry.date) + put("server", entry.server) + put("ping", entry.ping) + put("jitter", entry.jitter) + put("download", entry.download) + put("upload", entry.upload) + put("loss", entry.loss) + put("ipInfo", entry.ipInfo) + put("ipVersion", entry.ipVersion) + put("shareUrl", entry.shareUrl) + put("networkType", entry.networkType) + put("dlSamples", entry.downloadSamples.toJson()) + put("ulSamples", entry.uploadSamples.toJson()) + put("duration", entry.durationMs) + } + ) + + fun readAll(): List = query("SELECT * FROM history ORDER BY date DESC", null) + + fun read(id: Long): HistoryEntry? = query("SELECT * FROM history WHERE id=?", arrayOf(id.toString())).firstOrNull() + + fun delete(id: Long) { + writableDatabase.delete("history", "id=?", arrayOf(id.toString())) + } + + fun clear() { + writableDatabase.delete("history", null, null) + } + + private fun query(sql: String, args: Array?): List { + val result = mutableListOf() + readableDatabase.rawQuery(sql, args).use { cursor -> + while (cursor.moveToNext()) { + result.add( + HistoryEntry( + id = cursor.getLong(cursor.getColumnIndexOrThrow("id")), + date = cursor.getLong(cursor.getColumnIndexOrThrow("date")), + server = cursor.getString(cursor.getColumnIndexOrThrow("server")), + ping = cursor.getDouble(cursor.getColumnIndexOrThrow("ping")), + jitter = cursor.getDouble(cursor.getColumnIndexOrThrow("jitter")), + download = cursor.getDouble(cursor.getColumnIndexOrThrow("download")), + upload = cursor.getDouble(cursor.getColumnIndexOrThrow("upload")), + loss = cursor.getDouble(cursor.getColumnIndexOrThrow("loss")), + ipInfo = cursor.getString(cursor.getColumnIndexOrThrow("ipInfo")), + ipVersion = cursor.getInt(cursor.getColumnIndexOrThrow("ipVersion")), + shareUrl = cursor.getString(cursor.getColumnIndexOrThrow("shareUrl")), + networkType = cursor.getString(cursor.getColumnIndexOrThrow("networkType")), + downloadSamples = cursor.getString(cursor.getColumnIndexOrThrow("dlSamples")).fromJson(), + uploadSamples = cursor.getString(cursor.getColumnIndexOrThrow("ulSamples")).fromJson(), + durationMs = cursor.getLong(cursor.getColumnIndexOrThrow("duration")) + ) + ) + } + } + return result + } + + private fun List.toJson(): String { + val array = JSONArray() + forEach { array.put(it) } + return array.toString() + } + + private fun String?.fromJson(): List = try { + val array = JSONArray(this ?: "[]") + (0 until array.length()).map { array.getDouble(it) } + } catch (_: Exception) { + emptyList() + } + +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/NetworkInfo.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/NetworkInfo.kt new file mode 100644 index 0000000..9520141 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/data/NetworkInfo.kt @@ -0,0 +1,50 @@ +package org.librespeed.speedtest.data + +import android.content.Context +import android.net.ConnectivityManager +import android.net.NetworkCapabilities +import android.net.wifi.WifiInfo +import android.net.wifi.WifiManager +import android.os.Build + +object NetworkInfo { + + /** Best-effort description like "Wi-Fi 6", "Wi-Fi", "Ethernet" or "Cellular"; null when unknown. */ + fun describe(context: Context): String? { + return try { + val connectivity = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val capabilities = connectivity.getNetworkCapabilities(connectivity.activeNetwork) ?: return null + when { + capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> wifiName(context, capabilities) + capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> "Ethernet" + capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> "Cellular" + else -> null + } + } catch (_: Exception) { + null + } + } + + private fun wifiName(context: Context, capabilities: NetworkCapabilities): String { + val standard = try { + val info = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + capabilities.transportInfo as? WifiInfo + } else { + null + } ?: @Suppress("DEPRECATION") run { + (context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager)?.connectionInfo + } + if (info != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) info.wifiStandard else 0 + } catch (_: Exception) { + 0 + } + return when (standard) { + 8 -> "Wi-Fi 7" //ScanResult.WIFI_STANDARD_11BE + 6 -> "Wi-Fi 6" //WIFI_STANDARD_11AX + 5 -> "Wi-Fi 5" //WIFI_STANDARD_11AC + 4 -> "Wi-Fi 4" //WIFI_STANDARD_11N + else -> "Wi-Fi" + } + } + +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/engine/TestEngine.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/engine/TestEngine.kt new file mode 100644 index 0000000..2c0dad5 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/engine/TestEngine.kt @@ -0,0 +1,98 @@ +package org.librespeed.speedtest.engine + +import android.content.Context +import com.fdossena.speedtest.core.Speedtest +import com.fdossena.speedtest.core.config.SpeedtestConfig +import com.fdossena.speedtest.core.config.TelemetryConfig +import com.fdossena.speedtest.core.serverSelector.TestPoint +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withContext +import org.json.JSONArray +import org.json.JSONObject +import java.io.IOException +import kotlin.coroutines.resume + +class TestEngine(private val context: Context) { + + private var speedtest: Speedtest? = null + + data class Discovery(val servers: List, val selected: TestPoint?) + + /** + * Loads the server list (remote first, bundled fallback), pings all servers and picks the best one. + * [onListLoaded] gets the full list before any pinging starts. + */ + suspend fun discover( + customServers: List, + onListLoaded: (List) -> Unit = {} + ): Discovery = withContext(Dispatchers.IO) { + val st = newSpeedtest(telemetryEnabled = false) + customServers.forEach { runCatching { st.addTestPoint(it) } } + var loaded = false + val data = readAsset("ServerList.json")?.trim() + if (data != null) { + loaded = if (data.startsWith("\"") || data.startsWith("'")) { + st.loadServerList(data.substring(1, data.length - 1)) + } else { + runCatching { st.addTestPoints(JSONArray(data)); true }.getOrDefault(false) + } + } + if (!loaded) { + readAsset("ServerListFallback.json")?.let { + runCatching { st.addTestPoints(JSONArray(it)); loaded = true } + } + } + if (!loaded && customServers.isEmpty()) throw IOException("Failed to load the server list") + onListLoaded(st.testPoints.toList()) + val selected = suspendCancellableCoroutine { continuation -> + st.selectServer(object : Speedtest.ServerSelectedHandler() { + override fun onServerSelected(server: TestPoint?) { + continuation.resume(server) + } + }) + continuation.invokeOnCancellation { runCatching { st.abort() } } + } + Discovery(st.testPoints.toList(), selected) + } + + /** Prepares a fresh test run against an already known server, without re-pinging everything. */ + fun prepare(servers: List, selected: TestPoint, telemetryEnabled: Boolean, singleConnection: Boolean = false) { + val st = newSpeedtest(telemetryEnabled, singleConnection) + st.addTestPoints(servers.toTypedArray()) + st.setSelectedServer(selected) + speedtest = st + } + + fun start(handler: Speedtest.SpeedtestHandler) { + speedtest?.start(handler) + } + + fun abort() { + runCatching { speedtest?.abort() } + } + + private fun newSpeedtest(telemetryEnabled: Boolean, singleConnection: Boolean = false): Speedtest { + val st = Speedtest() + val configJson = runCatching { JSONObject(readAsset("SpeedtestConfig.json") ?: "{}") }.getOrDefault(JSONObject()) + if (singleConnection) { + configJson.put("dl_parallelStreams", 1) + configJson.put("ul_parallelStreams", 1) + } + runCatching { st.setSpeedtestConfig(SpeedtestConfig(configJson)) } + val telemetryJson = if (telemetryEnabled) { + JSONObject().put("telemetryLevel", TelemetryConfig.LEVEL_FULL) + } else { + readAsset("TelemetryConfig.json")?.let { runCatching { JSONObject(it) }.getOrNull() } ?: JSONObject() + } + runCatching { st.setTelemetryConfig(TelemetryConfig(telemetryJson)) } + return st + } + + private fun readAsset(name: String): String? = try { + context.assets.open(name).bufferedReader().use { it.readText() } + } catch (_: Exception) { + null + } + +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/share/ShareImage.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/share/ShareImage.kt new file mode 100644 index 0000000..0fe3749 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/share/ShareImage.kt @@ -0,0 +1,187 @@ +package org.librespeed.speedtest.share + +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.LinearGradient +import android.graphics.Paint +import android.graphics.Path +import android.graphics.RadialGradient +import android.graphics.Shader +import android.graphics.Typeface +import androidx.core.content.FileProvider +import org.librespeed.speedtest.R +import org.librespeed.speedtest.data.GeoDistance +import org.librespeed.speedtest.data.HistoryEntry +import org.librespeed.speedtest.ui.history.formatDate +import java.io.File +import java.util.Locale + +object ShareImage { + + private const val TEAL = 0xFF2DD4BF.toInt() + private const val PURPLE = 0xFFA78BFA.toInt() + private const val WHITE = 0xFFE4E9F2.toInt() + private const val GRAY = 0xFF9AA4B8.toInt() + private const val BACKGROUND_TOP = 0xFF0B1120.toInt() + private const val BACKGROUND_BOTTOM = 0xFF1A1440.toInt() + + private const val WIDTH = 1080 + private const val HEIGHT = 1350 + + fun share(context: Context, entry: HistoryEntry, useMBytes: Boolean) { + try { + val bitmap = render(context, entry, useMBytes) + val directory = File(context.cacheDir, "share").apply { mkdirs() } + val file = File(directory, "librespeed-result.png") + file.outputStream().use { bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) } + bitmap.recycle() + val uri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file) + val intent = Intent(Intent.ACTION_SEND).apply { + type = "image/png" + putExtra(Intent.EXTRA_STREAM, uri) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + } + context.startActivity(Intent.createChooser(intent, context.getString(R.string.share_result))) + } catch (_: Exception) { + } + } + + fun render(context: Context, entry: HistoryEntry, useMBytes: Boolean): Bitmap { + val bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + drawBackground(canvas) + + val unit = context.getString(if (useMBytes) R.string.unit_mbytes else R.string.unit_mbps) + fun speed(value: Double) = + if (value < 0) "—" else String.format(Locale.getDefault(), "%.2f", if (useMBytes) value / 8 else value) + fun ms(value: Double) = + if (value < 0) "—" else String.format(Locale.getDefault(), "%.0f %s", value, context.getString(R.string.unit_ms)) + + fun paint(color: Int, size: Float, bold: Boolean = false) = Paint(Paint.ANTI_ALIAS_FLAG).apply { + this.color = color + textSize = size + typeface = if (bold) Typeface.create(Typeface.DEFAULT, Typeface.BOLD) else Typeface.DEFAULT + textAlign = Paint.Align.CENTER + } + + val centerX = WIDTH / 2f + + //wordmark + val titlePaint = paint(TEAL, 92f, bold = true).apply { textAlign = Paint.Align.LEFT } + val libreWidth = titlePaint.measureText("Libre") + val speedWidth = titlePaint.measureText("Speed") + val titleStart = centerX - (libreWidth + speedWidth) / 2 + canvas.drawText("Libre", titleStart, 170f, titlePaint) + titlePaint.color = WHITE + canvas.drawText("Speed", titleStart + libreWidth, 170f, titlePaint) + canvas.drawText(context.getString(R.string.share_image_subtitle), centerX, 235f, paint(GRAY, 42f)) + + //download + drawCircleArrow(canvas, centerX - measureSpeedHalf(speed(entry.download)) - 70f, 425f, TEAL, down = true) + canvas.drawText(speed(entry.download), centerX, 460f, paint(TEAL, 140f, bold = true)) + canvas.drawText(unit, centerX + measureSpeedHalf(speed(entry.download)) + 85f, 455f, paint(GRAY, 46f)) + canvas.drawText(context.getString(R.string.test_download).uppercase(Locale.ROOT), centerX, 535f, paint(GRAY, 44f, bold = true)) + + //upload + drawCircleArrow(canvas, centerX - measureSpeedHalf(speed(entry.upload)) - 70f, 690f, PURPLE, down = false) + canvas.drawText(speed(entry.upload), centerX, 725f, paint(PURPLE, 140f, bold = true)) + canvas.drawText(unit, centerX + measureSpeedHalf(speed(entry.upload)) + 85f, 720f, paint(GRAY, 46f)) + canvas.drawText(context.getString(R.string.test_upload).uppercase(Locale.ROOT), centerX, 800f, paint(GRAY, 44f, bold = true)) + + //ping + jitter + val leftX = WIDTH / 3f + val rightX = 2 * WIDTH / 3f + canvas.drawText(ms(entry.ping), leftX, 950f, paint(WHITE, 72f, bold = true)) + canvas.drawText(context.getString(R.string.test_ping).uppercase(Locale.ROOT), leftX, 1005f, paint(GRAY, 40f)) + canvas.drawText(ms(entry.jitter), rightX, 950f, paint(WHITE, 72f, bold = true)) + canvas.drawText(context.getString(R.string.test_jitter).uppercase(Locale.ROOT), rightX, 1005f, paint(GRAY, 40f)) + + //server + date, above the waves + canvas.drawText( + listOfNotNull(GeoDistance.cleanName(entry.server), GeoDistance.sponsor(entry.server)).joinToString(" · "), + centerX, 1075f, paint(WHITE, 44f) + ) + canvas.drawText(formatDate(entry.date), centerX, 1133f, paint(GRAY, 40f)) + + //rounded border framing the whole card, like the mockup + canvas.drawRoundRect( + android.graphics.RectF(5f, 5f, WIDTH - 5f, HEIGHT - 5f), 48f, 48f, + Paint(Paint.ANTI_ALIAS_FLAG).apply { + color = 0x30FFFFFF + style = Paint.Style.STROKE + strokeWidth = 5f + } + ) + + return bitmap + } + + private fun measureSpeedHalf(text: String): Float = + Paint(Paint.ANTI_ALIAS_FLAG).apply { + textSize = 140f + typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD) + }.measureText(text) / 2 + + private fun drawBackground(canvas: Canvas) { + val width = WIDTH.toFloat() + val height = HEIGHT.toFloat() + canvas.drawRect(0f, 0f, width, height, Paint().apply { + shader = LinearGradient(0f, 0f, 0f, height, BACKGROUND_TOP, BACKGROUND_BOTTOM, Shader.TileMode.CLAMP) + }) + //soft teal glow behind the wordmark and purple glow behind the upload value + canvas.drawRect(0f, 0f, width, 500f, Paint().apply { + shader = RadialGradient(width / 2f, 60f, 620f, 0x2E2DD4BF, 0x002DD4BF, Shader.TileMode.CLAMP) + }) + canvas.drawRect(0f, 350f, width, height, Paint().apply { + shader = RadialGradient(width / 2f, 700f, 760f, 0x1E7C5CFC, 0x007C5CFC, Shader.TileMode.CLAMP) + }) + //subtle gradient waves along the very bottom, below the server line + wave(canvas, height - 210f, 70f, 0x2E2DD4BF, 0x2EA78BFA, phase = 0f) + wave(canvas, height - 145f, 60f, 0x38A78BFA, 0x382DD4BF, phase = 0.5f) + wave(canvas, height - 80f, 55f, 0x4D2DD4BF, 0x4D7C5CFC, phase = 0.25f) + } + + private fun wave(canvas: Canvas, top: Float, amplitude: Float, colorStart: Int, colorEnd: Int, phase: Float) { + val width = WIDTH.toFloat() + val height = HEIGHT.toFloat() + val path = Path().apply { + moveTo(0f, top + amplitude * phase) + cubicTo( + width * 0.25f, top - amplitude, + width * 0.45f, top + amplitude * 1.4f, + width * 0.7f, top + amplitude * 0.2f + ) + cubicTo( + width * 0.85f, top - amplitude * 0.5f, + width * 0.95f, top + amplitude * 0.6f, + width, top - amplitude * 0.2f + ) + lineTo(width, height) + lineTo(0f, height) + close() + } + canvas.drawPath(path, Paint(Paint.ANTI_ALIAS_FLAG).apply { + shader = LinearGradient(0f, top - amplitude, width, height, colorStart, colorEnd, Shader.TileMode.CLAMP) + }) + } + + private fun drawCircleArrow(canvas: Canvas, cx: Float, cy: Float, color: Int, down: Boolean) { + val radius = 36f + val stroke = Paint(Paint.ANTI_ALIAS_FLAG).apply { + this.color = color + style = Paint.Style.STROKE + strokeWidth = 6f + strokeCap = Paint.Cap.ROUND + } + canvas.drawCircle(cx, cy, radius, stroke) + val shaft = 17f + val head = 10f + val direction = if (down) 1f else -1f + canvas.drawLine(cx, cy - shaft * direction, cx, cy + shaft * direction, stroke) + canvas.drawLine(cx, cy + shaft * direction, cx - head, cy + (shaft - head) * direction, stroke) + canvas.drawLine(cx, cy + shaft * direction, cx + head, cy + (shaft - head) * direction, stroke) + } + +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/share/ShareResult.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/share/ShareResult.kt new file mode 100644 index 0000000..7e0bc8d --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/share/ShareResult.kt @@ -0,0 +1,94 @@ +package org.librespeed.speedtest.share + +import android.content.Context +import android.content.Intent +import org.librespeed.speedtest.R +import org.librespeed.speedtest.data.GeoDistance +import java.util.Locale + +object ShareResult { + + fun copy(context: Context, text: String) { + try { + val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager + clipboard.setPrimaryClip(android.content.ClipData.newPlainText("LibreSpeed", text)) + } catch (_: Exception) { + } + } + + fun shareLink(context: Context, url: String) { + val intent = Intent(Intent.ACTION_SEND).apply { + type = "text/plain" + putExtra(Intent.EXTRA_TEXT, url) + } + try { + context.startActivity(Intent.createChooser(intent, context.getString(R.string.share_result))) + } catch (_: Exception) { + } + } + + fun buildText( + context: Context, + server: String, + download: Double, + upload: Double, + ping: Double, + jitter: Double, + loss: Double, + useMBytes: Boolean, + shareUrl: String?, + networkType: String? = null, + ipVersion: Int = 0 + ): String { + val unit = context.getString(if (useMBytes) R.string.unit_mbytes else R.string.unit_mbps) + fun speed(value: Double) = + if (value < 0) "—" + else String.format(Locale.getDefault(), "%.2f %s", if (useMBytes) value / 8 else value, unit) + + fun number(value: Double) = + if (value < 0) "—" else String.format(Locale.getDefault(), "%.1f", value) + + return buildString { + appendLine( + context.getString( + R.string.share_text, + speed(download), speed(upload), number(ping), number(jitter), + GeoDistance.cleanName(server) + ) + ) + if (loss >= 0) { + appendLine(context.getString(R.string.share_text_loss, number(loss))) + } + networkType?.let { appendLine(context.getString(R.string.share_text_network, it)) } + if (ipVersion != 0) { + appendLine(context.getString(R.string.share_text_protocol, ipVersion)) + } + shareUrl?.let { appendLine(it) } + }.trimEnd() + } + + fun share( + context: Context, + server: String, + download: Double, + upload: Double, + ping: Double, + jitter: Double, + loss: Double, + useMBytes: Boolean, + shareUrl: String?, + networkType: String? = null, + ipVersion: Int = 0 + ) { + val text = buildText(context, server, download, upload, ping, jitter, loss, useMBytes, shareUrl, networkType, ipVersion) + val intent = Intent(Intent.ACTION_SEND).apply { + type = "text/plain" + putExtra(Intent.EXTRA_TEXT, text) + } + try { + context.startActivity(Intent.createChooser(intent, context.getString(R.string.share_result))) + } catch (_: Exception) { + } + } + +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/App.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/App.kt new file mode 100644 index 0000000..9f08f05 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/App.kt @@ -0,0 +1,162 @@ +package org.librespeed.speedtest.ui + +import androidx.annotation.StringRes +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.History +import androidx.compose.material.icons.filled.Public +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material.icons.filled.Speed +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.NavigationRail +import androidx.compose.material3.NavigationRailItem +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.stringResource +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavGraph.Companion.findStartDestination +import androidx.navigation.NavHostController +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument +import org.librespeed.speedtest.R +import org.librespeed.speedtest.ui.history.HistoryScreen +import org.librespeed.speedtest.ui.result.ResultScreen +import org.librespeed.speedtest.ui.servers.ServersScreen +import org.librespeed.speedtest.ui.settings.SettingsScreen +import org.librespeed.speedtest.ui.speedtest.SpeedtestScreen +import org.librespeed.speedtest.ui.speedtest.SpeedtestViewModel + +enum class Destination(val route: String, @StringRes val label: Int, val icon: ImageVector) { + SPEEDTEST("speedtest", R.string.nav_speedtest, Icons.Filled.Speed), + HISTORY("history", R.string.nav_history, Icons.Filled.History), + SERVERS("servers", R.string.nav_servers, Icons.Filled.Public), + SETTINGS("settings", R.string.nav_settings, Icons.Filled.Settings) +} + +@androidx.compose.material3.ExperimentalMaterial3Api +@Composable +fun App(windowWidth: WindowWidthSizeClass = WindowWidthSizeClass.Compact) { + val navController = rememberNavController() + val backStackEntry by navController.currentBackStackEntryAsState() + val currentRoute = backStackEntry?.destination?.route + val speedtestViewModel: SpeedtestViewModel = viewModel() + val useRail = windowWidth != WindowWidthSizeClass.Compact + val onResultScreen = currentRoute?.startsWith("result/") == true || + currentRoute?.startsWith("testdetails/") == true || + currentRoute?.startsWith("share/") == true + + Scaffold( + containerColor = MaterialTheme.colorScheme.background, + bottomBar = { + if (!useRail && !onResultScreen) { + NavigationBar { + Destination.entries.forEach { destination -> + NavigationBarItem( + selected = currentRoute == destination.route, + onClick = { navController.navigateTo(destination) }, + icon = { Icon(destination.icon, contentDescription = null) }, + label = { Text(stringResource(destination.label)) } + ) + } + } + } + } + ) { padding -> + Row(Modifier.fillMaxSize().padding(padding)) { + if (useRail && !onResultScreen) { + NavigationRail { + Destination.entries.forEach { destination -> + NavigationRailItem( + selected = currentRoute == destination.route, + onClick = { navController.navigateTo(destination) }, + icon = { Icon(destination.icon, contentDescription = null) }, + label = { Text(stringResource(destination.label)) } + ) + } + } + } + NavHost( + navController = navController, + startDestination = Destination.SPEEDTEST.route, + modifier = Modifier.fillMaxSize() + ) { + composable(Destination.SPEEDTEST.route) { + SpeedtestScreen( + viewModel = speedtestViewModel, + onServersClick = { navController.navigateTo(Destination.SERVERS) }, + onSettingsClick = { navController.navigateTo(Destination.SETTINGS) }, + onResult = { id -> navController.navigate("result/$id") } + ) + } + composable(Destination.HISTORY.route) { + HistoryScreen(onOpen = { id -> navController.navigate("result/$id") }) + } + composable(Destination.SERVERS.route) { ServersScreen(speedtestViewModel) } + composable(Destination.SETTINGS.route) { + val uiState by speedtestViewModel.state.collectAsStateWithLifecycle() + SettingsScreen( + serverLabel = uiState.selectedServer?.name, + serverPinned = uiState.pinnedServer, + onServersClick = { navController.navigateTo(Destination.SERVERS) } + ) + } + composable( + route = "result/{id}", + arguments = listOf(navArgument("id") { type = NavType.LongType }) + ) { entry -> + ResultScreen( + entryId = entry.arguments?.getLong("id") ?: 0L, + onBack = { navController.popBackStack() }, + onTestAgain = { serverName -> + navController.navigateTo(Destination.SPEEDTEST) + speedtestViewModel.testAgain(serverName) + }, + onTestDetails = { id -> navController.navigate("testdetails/$id") }, + onShare = { id -> navController.navigate("share/$id") } + ) + } + composable( + route = "testdetails/{id}", + arguments = listOf(navArgument("id") { type = NavType.LongType }) + ) { entry -> + org.librespeed.speedtest.ui.result.TestDetailsScreen( + entryId = entry.arguments?.getLong("id") ?: 0L, + onBack = { navController.popBackStack() } + ) + } + composable( + route = "share/{id}", + arguments = listOf(navArgument("id") { type = NavType.LongType }) + ) { entry -> + org.librespeed.speedtest.ui.result.ShareScreen( + entryId = entry.arguments?.getLong("id") ?: 0L, + onBack = { navController.popBackStack() } + ) + } + } + } + } +} + +private fun NavHostController.navigateTo(destination: Destination) { + navigate(destination.route) { + popUpTo(graph.findStartDestination().id) { saveState = true } + launchSingleTop = true + restoreState = true + } +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/components/Sparkline.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/components/Sparkline.kt new file mode 100644 index 0000000..03bb2e1 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/components/Sparkline.kt @@ -0,0 +1,51 @@ +package org.librespeed.speedtest.ui.components + +import androidx.compose.foundation.Canvas +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.drawscope.Stroke + +@Composable +fun Sparkline( + data: List, + color: Color, + modifier: Modifier = Modifier +) { + Canvas(modifier = modifier) { + if (data.size < 2) return@Canvas + val max = data.max().takeIf { it > 0 } ?: return@Canvas + val stepX = size.width / (data.size - 1) + val vPadding = size.height * 0.1f + val usable = size.height - vPadding * 2 + fun pointAt(index: Int): Offset { + val y = size.height - vPadding - (data[index] / max * usable).toFloat() + return Offset(stepX * index, y) + } + + val line = Path() + line.moveTo(pointAt(0).x, pointAt(0).y) + for (i in 1 until data.size) { + val previous = pointAt(i - 1) + val current = pointAt(i) + val midX = (previous.x + current.x) / 2 + line.cubicTo(midX, previous.y, midX, current.y, current.x, current.y) + } + drawPath(line, color = color, style = Stroke(width = 4f, cap = StrokeCap.Round)) + + val fill = Path().apply { + addPath(line) + lineTo(size.width, size.height) + lineTo(0f, size.height) + close() + } + drawPath( + fill, + brush = Brush.verticalGradient(listOf(color.copy(alpha = 0.25f), Color.Transparent)) + ) + } +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/components/SpeedGauge.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/components/SpeedGauge.kt new file mode 100644 index 0000000..55e7be2 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/components/SpeedGauge.kt @@ -0,0 +1,123 @@ +package org.librespeed.speedtest.ui.components + +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.graphics.drawscope.rotate +import androidx.compose.ui.graphics.nativeCanvas +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import org.librespeed.speedtest.ui.theme.LocalSpeedAccents +import java.util.Locale +import kotlin.math.cos +import kotlin.math.sin + +private val SCALE_STOPS = doubleArrayOf(0.0, 1.0, 5.0, 10.0, 25.0, 50.0, 100.0, 250.0, 500.0, 1000.0) +//the MB/s dial is not the Mbps dial divided by 8: that would label awkward stops like 31.25 +private val SCALE_STOPS_MBYTES = doubleArrayOf(0.0, 0.5, 1.0, 2.5, 5.0, 10.0, 25.0, 50.0, 100.0, 125.0) +private const val START_ANGLE = 135f +private const val SWEEP = 270f + +/** Maps a speed to a 0..1 position on the non-linear gauge scale. */ +private fun scaleFraction(speed: Double, stops: DoubleArray): Float { + if (speed <= 0) return 0f + if (speed >= stops.last()) return 1f + for (i in 1 until stops.size) { + if (speed <= stops[i]) { + val segment = (speed - stops[i - 1]) / (stops[i] - stops[i - 1]) + return ((i - 1) + segment).toFloat() / (stops.size - 1) + } + } + return 1f +} + +/** [speed] is always in Mbps; [useMBytes] converts the dial to match a MB/s readout. */ +@Composable +fun SpeedGauge( + speed: Double, + modifier: Modifier = Modifier, + useMBytes: Boolean = false, + content: @Composable () -> Unit +) { + val stops = if (useMBytes) SCALE_STOPS_MBYTES else SCALE_STOPS + val fraction by animateFloatAsState( + targetValue = scaleFraction(if (useMBytes) speed / 8 else speed, stops), + animationSpec = tween(durationMillis = 300), + label = "gauge" + ) + val accents = LocalSpeedAccents.current + val trackColor = MaterialTheme.colorScheme.surfaceVariant + val labelColor = MaterialTheme.colorScheme.onSurfaceVariant + val labelSizePx = with(LocalDensity.current) { 11.sp.toPx() } + + Box(modifier = modifier.aspectRatio(1f), contentAlignment = Alignment.Center) { + Canvas(modifier = Modifier.matchParentSize()) { + val stroke = size.minDimension * 0.055f + val labelInset = labelSizePx * 2.2f + val diameter = size.minDimension - stroke - labelInset * 2 + val topLeft = Offset((size.width - diameter) / 2, (size.height - diameter) / 2) + val arcSize = Size(diameter, diameter) + + drawArc( + color = trackColor, + startAngle = START_ANGLE, + sweepAngle = SWEEP, + useCenter = false, + topLeft = topLeft, + size = arcSize, + style = Stroke(width = stroke, cap = StrokeCap.Round) + ) + if (fraction > 0f) { + // sweep gradient starts at 3 o'clock; rotate so it begins at the gauge start + rotate(degrees = START_ANGLE - 5f) { + drawArc( + brush = Brush.sweepGradient( + 0f to accents.download, + (SWEEP + 10f) / 360f to accents.upload, + 1f to accents.download + ), + startAngle = 5f, + sweepAngle = (SWEEP * fraction).coerceAtLeast(1f), + useCenter = false, + topLeft = topLeft, + size = arcSize, + style = Stroke(width = stroke, cap = StrokeCap.Round) + ) + } + } + // scale labels + val paint = android.graphics.Paint().apply { + color = labelColor.toArgb() + textSize = labelSizePx + textAlign = android.graphics.Paint.Align.CENTER + isAntiAlias = true + } + val labelRadius = diameter / 2 + stroke / 2 + labelSizePx * 1.1f + val center = Offset(size.width / 2, size.height / 2) + stops.forEachIndexed { index, stop -> + val angleDeg = START_ANGLE + SWEEP * index / (stops.size - 1) + val rad = Math.toRadians(angleDeg.toDouble()) + val x = center.x + labelRadius * cos(rad).toFloat() + val y = center.y + labelRadius * sin(rad).toFloat() + labelSizePx * 0.35f + val text = if (stop % 1.0 == 0.0) stop.toInt().toString() + else String.format(Locale.getDefault(), "%.1f", stop) + drawContext.canvas.nativeCanvas.drawText(text, x, y, paint) + } + } + content() + } +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/history/HistoryScreen.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/history/HistoryScreen.kt new file mode 100644 index 0000000..c98cda6 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/history/HistoryScreen.kt @@ -0,0 +1,189 @@ +package org.librespeed.speedtest.ui.history + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ChevronRight +import androidx.compose.material.icons.filled.DeleteOutline +import androidx.compose.material.icons.filled.Public +import androidx.compose.material.icons.filled.SettingsEthernet +import androidx.compose.material.icons.filled.SignalCellularAlt +import androidx.compose.material.icons.filled.Wifi +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewmodel.compose.viewModel +import org.librespeed.speedtest.R +import org.librespeed.speedtest.data.GeoDistance +import org.librespeed.speedtest.data.HistoryEntry +import org.librespeed.speedtest.ui.theme.Purple +import org.librespeed.speedtest.ui.theme.Teal +import java.text.DateFormat +import java.util.Date +import java.util.Locale + +@Composable +fun HistoryScreen( + onOpen: (Long) -> Unit, + viewModel: HistoryViewModel = viewModel() +) { + val entries by viewModel.entries.collectAsStateWithLifecycle() + var confirmClear by remember { mutableStateOf(false) } + + LaunchedEffect(Unit) { viewModel.load() } + + Column(Modifier.fillMaxSize()) { + Row( + modifier = Modifier.fillMaxWidth().padding(start = 20.dp, end = 8.dp, top = 8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(R.string.nav_history), + style = MaterialTheme.typography.headlineSmall, + color = MaterialTheme.colorScheme.onBackground, + modifier = Modifier.weight(1f) + ) + IconButton(onClick = { confirmClear = true }, enabled = entries.isNotEmpty()) { + Icon(Icons.Filled.DeleteOutline, contentDescription = stringResource(R.string.history_clear)) + } + } + if (entries.isEmpty()) { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Text( + text = stringResource(R.string.history_empty), + color = MaterialTheme.colorScheme.onSurfaceVariant, + style = MaterialTheme.typography.bodyMedium + ) + } + } else { + LazyColumn(Modifier.fillMaxSize(), contentPadding = PaddingValues(16.dp)) { + items(entries, key = { it.id }) { entry -> + HistoryRow(entry = entry, onClick = { onOpen(entry.id) }) + Spacer(Modifier.height(8.dp)) + } + } + } + } + + if (confirmClear) { + AlertDialog( + onDismissRequest = { confirmClear = false }, + title = { Text(stringResource(R.string.history_clear)) }, + text = { Text(stringResource(R.string.history_clear_confirm)) }, + confirmButton = { + TextButton(onClick = { + confirmClear = false + viewModel.clear() + }) { Text(stringResource(R.string.history_clear)) } + }, + dismissButton = { + TextButton(onClick = { confirmClear = false }) { Text(stringResource(R.string.dialog_cancel)) } + } + ) + } +} + +fun formatDate(timestamp: Long): String = + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT).format(Date(timestamp)) + +@Composable +private fun HistoryRow(entry: HistoryEntry, onClick: () -> Unit) { + Card( + onClick = onClick, + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), + modifier = Modifier.fillMaxWidth() + ) { + Row( + modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = when { + entry.networkType == null -> Icons.Filled.Public + entry.networkType.startsWith("Wi-Fi") -> Icons.Filled.Wifi + entry.networkType == "Ethernet" -> Icons.Filled.SettingsEthernet + else -> Icons.Filled.SignalCellularAlt + }, + contentDescription = entry.networkType, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.size(20.dp) + ) + Spacer(Modifier.width(12.dp)) + Column(Modifier.weight(1f)) { + Text( + text = listOfNotNull(formatDate(entry.date), entry.networkType).joinToString(" • "), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Text( + text = GeoDistance.cleanName(entry.server), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + Column(horizontalAlignment = Alignment.End) { + Text( + text = String.format(Locale.US, "%.0f", entry.download), + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.SemiBold, + color = Teal + ) + Text( + text = stringResource(R.string.unit_mbps), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Spacer(Modifier.width(14.dp)) + Column(horizontalAlignment = Alignment.End) { + Text( + text = String.format(Locale.US, "%.0f", entry.upload), + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.SemiBold, + color = Purple + ) + Text( + text = stringResource(R.string.unit_mbps), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Icon( + Icons.Filled.ChevronRight, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/history/HistoryViewModel.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/history/HistoryViewModel.kt new file mode 100644 index 0000000..fe2050c --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/history/HistoryViewModel.kt @@ -0,0 +1,40 @@ +package org.librespeed.speedtest.ui.history + +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.librespeed.speedtest.data.HistoryDatabase +import org.librespeed.speedtest.data.HistoryEntry + +class HistoryViewModel(application: Application) : AndroidViewModel(application) { + + private val database = HistoryDatabase(application) + private val _entries = MutableStateFlow>(emptyList()) + val entries: StateFlow> = _entries + + fun load() { + viewModelScope.launch { + _entries.value = withContext(Dispatchers.IO) { database.readAll() } + } + } + + fun delete(entry: HistoryEntry) { + viewModelScope.launch { + withContext(Dispatchers.IO) { database.delete(entry.id) } + load() + } + } + + fun clear() { + viewModelScope.launch { + withContext(Dispatchers.IO) { database.clear() } + load() + } + } + +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/result/ResultScreen.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/result/ResultScreen.kt new file mode 100644 index 0000000..e866cb7 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/result/ResultScreen.kt @@ -0,0 +1,410 @@ +package org.librespeed.speedtest.ui.result + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.ChevronRight +import androidx.compose.material.icons.filled.DataUsage +import androidx.compose.material.icons.filled.Lan +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material.icons.filled.MyLocation +import androidx.compose.material.icons.filled.NetworkPing +import androidx.compose.material.icons.filled.PhoneAndroid +import androidx.compose.material.icons.filled.Public +import androidx.compose.material.icons.filled.Refresh +import androidx.compose.material.icons.filled.Schedule +import androidx.compose.material.icons.filled.Share +import androidx.compose.material.icons.filled.SsidChart +import androidx.compose.material.icons.filled.Tag +import androidx.compose.material.icons.outlined.ArrowCircleDown +import androidx.compose.material.icons.outlined.ArrowCircleUp +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.librespeed.speedtest.R +import org.librespeed.speedtest.data.AppPreferences +import org.librespeed.speedtest.data.GeoDistance +import org.librespeed.speedtest.data.HistoryDatabase +import org.librespeed.speedtest.data.HistoryEntry +import org.librespeed.speedtest.share.ShareResult +import org.librespeed.speedtest.ui.components.Sparkline +import org.librespeed.speedtest.ui.history.formatDate +import org.librespeed.speedtest.ui.theme.Purple +import org.librespeed.speedtest.ui.theme.Teal +import java.util.Locale + +@Composable +fun ResultScreen( + entryId: Long, + onBack: () -> Unit, + onTestAgain: (String) -> Unit, + onTestDetails: (Long) -> Unit, + onShare: (Long) -> Unit +) { + val context = LocalContext.current + val prefs = remember { AppPreferences(context.applicationContext) } + val useMBytes by prefs.useMBytes.collectAsStateWithLifecycle(initialValue = false) + var entry by remember { mutableStateOf(null) } + var missing by remember { mutableStateOf(false) } + var menuOpen by remember { mutableStateOf(false) } + + LaunchedEffect(entryId) { + val loaded = withContext(Dispatchers.IO) { HistoryDatabase(context.applicationContext).read(entryId) } + if (loaded == null) missing = true else entry = loaded + } + LaunchedEffect(missing) { if (missing) onBack() } + + val result = entry ?: return + val unitLabel = stringResource(if (useMBytes) R.string.unit_mbytes else R.string.unit_mbps) + fun display(value: Double): Double = if (useMBytes) value / 8 else value + + fun copyText() { + ShareResult.copy( + context, + ShareResult.buildText( + context, result.server, result.download, result.upload, result.ping, + result.jitter, result.loss, useMBytes, result.shareUrl, + result.networkType, result.ipVersion + ) + ) + } + + Column( + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Row( + modifier = Modifier.fillMaxWidth().padding(start = 4.dp, end = 4.dp, top = 4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + IconButton(onClick = onBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(R.string.dialog_close)) + } + Text( + text = stringResource(R.string.result_title), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onBackground, + textAlign = TextAlign.Center, + modifier = Modifier.weight(1f) + ) + IconButton(onClick = { onShare(result.id) }) { + Icon(Icons.Filled.Share, contentDescription = stringResource(R.string.share_result), tint = MaterialTheme.colorScheme.onSurfaceVariant) + } + Box { + IconButton(onClick = { menuOpen = true }) { + Icon(Icons.Filled.MoreVert, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant) + } + DropdownMenu(expanded = menuOpen, onDismissRequest = { menuOpen = false }) { + DropdownMenuItem( + text = { Text(stringResource(R.string.test_details_title)) }, + onClick = { + menuOpen = false + onTestDetails(result.id) + } + ) + DropdownMenuItem( + text = { Text(stringResource(R.string.share_copy)) }, + onClick = { + menuOpen = false + copyText() + } + ) + val deleteScope = rememberCoroutineScope() + DropdownMenuItem( + text = { Text(stringResource(R.string.history_delete), color = MaterialTheme.colorScheme.error) }, + onClick = { + menuOpen = false + deleteScope.launch(Dispatchers.IO) { + HistoryDatabase(context.applicationContext).delete(result.id) + } + onBack() + } + ) + } + } + } + + Column(Modifier.widthIn(max = 560.dp).fillMaxWidth().padding(horizontal = 24.dp)) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth().padding(top = 4.dp, bottom = 12.dp) + ) { + Icon( + Icons.Filled.Public, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(18.dp) + ) + Spacer(Modifier.width(10.dp)) + Column { + Text( + text = formatDate(result.date), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = listOfNotNull( + GeoDistance.cleanName(result.server), + GeoDistance.sponsor(result.server) + ).joinToString(" · "), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + + Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { + SpeedCard( + modifier = Modifier.weight(1f), + icon = Icons.Outlined.ArrowCircleDown, + label = stringResource(R.string.test_download), + value = display(result.download), + unit = unitLabel, + accent = Teal, + samples = result.downloadSamples + ) + SpeedCard( + modifier = Modifier.weight(1f), + icon = Icons.Outlined.ArrowCircleUp, + label = stringResource(R.string.test_upload), + value = display(result.upload), + unit = unitLabel, + accent = Purple, + samples = result.uploadSamples + ) + } + + Spacer(Modifier.height(12.dp)) + Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { + MetricBox(Modifier.weight(1f), Icons.Filled.NetworkPing, stringResource(R.string.test_ping), result.ping, stringResource(R.string.unit_ms)) + MetricBox(Modifier.weight(1f), Icons.Filled.SsidChart, stringResource(R.string.test_jitter), result.jitter, stringResource(R.string.unit_ms)) + } + + Spacer(Modifier.height(16.dp)) + Card(colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)) { + Column(Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 4.dp)) { + if (result.ipVersion != 0) { + DetailRow(stringResource(R.string.detail_protocol), "IPv${result.ipVersion}", Icons.Filled.Lan) + RowDivider() + } + result.ipInfo?.takeIf { it.isNotBlank() }?.let { info -> + DetailRow(stringResource(R.string.detail_ip), info.substringBefore(" - ").trim(), Icons.Filled.MyLocation) + RowDivider() + } + DetailRow(stringResource(R.string.detail_client), "Android ${android.os.Build.VERSION.RELEASE}", Icons.Filled.PhoneAndroid) + RowDivider() + DetailRow(stringResource(R.string.detail_server), GeoDistance.cleanName(result.server), Icons.Filled.Public) + result.shareUrl?.let { + RowDivider() + DetailRow(stringResource(R.string.detail_result_id), it.substringAfterLast("=", it), Icons.Filled.Tag) + } + if (result.durationMs > 0) { + RowDivider() + DetailRow(stringResource(R.string.detail_duration), String.format(Locale.US, "%.1f s", result.durationMs / 1000.0), Icons.Filled.Schedule) + } + val totalMb = (result.downloadSamples.sum() + result.uploadSamples.sum()) * 0.1 / 8 + if (totalMb > 0) { + RowDivider() + DetailRow(stringResource(R.string.detail_data), String.format(Locale.US, "~ %.0f MB", totalMb), Icons.Filled.DataUsage) + } + } + } + + Spacer(Modifier.height(16.dp)) + Button( + onClick = { onShare(result.id) }, + modifier = Modifier.fillMaxWidth().height(52.dp) + ) { + Icon(Icons.Filled.Share, contentDescription = null, modifier = Modifier.size(18.dp)) + Spacer(Modifier.width(8.dp)) + Text(stringResource(R.string.share_result), style = MaterialTheme.typography.titleMedium) + } + Spacer(Modifier.height(8.dp)) + OutlinedButton( + onClick = { onTestAgain(result.server) }, + border = BorderStroke(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.6f)), + colors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.colorScheme.primary), + modifier = Modifier.fillMaxWidth().height(52.dp) + ) { + Icon(Icons.Filled.Refresh, contentDescription = null, modifier = Modifier.size(18.dp)) + Spacer(Modifier.width(8.dp)) + Text(stringResource(R.string.result_test_again), style = MaterialTheme.typography.titleMedium) + } + + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { onTestDetails(result.id) } + .padding(vertical = 14.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(R.string.more_details), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.weight(1f) + ) + Icon( + Icons.Filled.ChevronRight, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary + ) + } + Spacer(Modifier.height(12.dp)) + } + } +} + +@Composable +private fun SpeedCard( + modifier: Modifier, + icon: ImageVector, + label: String, + value: Double, + unit: String, + accent: Color, + samples: List +) { + Card(modifier = modifier, colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)) { + Column(Modifier.padding(12.dp)) { + Row(verticalAlignment = Alignment.CenterVertically) { + Icon(icon, contentDescription = null, tint = accent, modifier = Modifier.size(16.dp)) + Spacer(Modifier.width(6.dp)) + Text( + text = label.uppercase(Locale.ROOT), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Spacer(Modifier.height(4.dp)) + Text( + text = String.format(Locale.US, "%.2f", value), + style = MaterialTheme.typography.headlineSmall, + fontWeight = FontWeight.Bold, + color = accent + ) + Text( + text = unit, + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + if (samples.size > 1) { + Sparkline( + data = samples, + color = accent, + modifier = Modifier.fillMaxWidth().height(30.dp).padding(top = 4.dp) + ) + } + } + } +} + +@Composable +private fun MetricBox(modifier: Modifier, icon: ImageVector, title: String, value: Double, unit: String) { + Card(modifier = modifier, colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)) { + Column(Modifier.padding(vertical = 14.dp).fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { + Row(verticalAlignment = Alignment.CenterVertically) { + Icon(icon, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.size(13.dp)) + Spacer(Modifier.width(4.dp)) + Text( + text = title.uppercase(Locale.ROOT), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Spacer(Modifier.height(4.dp)) + Row(verticalAlignment = Alignment.Bottom) { + Text( + text = if (value < 0) "—" else String.format(Locale.US, "%.1f", value), + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary + ) + Spacer(Modifier.width(4.dp)) + Text( + text = unit, + modifier = Modifier.padding(bottom = 3.dp), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + } +} + +@Composable +internal fun DetailRow(title: String, value: String, icon: ImageVector? = null) { + Row(Modifier.fillMaxWidth().padding(vertical = 9.dp), verticalAlignment = Alignment.CenterVertically) { + icon?.let { + Icon( + it, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.size(16.dp) + ) + Spacer(Modifier.width(10.dp)) + } + Text( + text = title, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(Modifier.width(16.dp)) + Text( + text = value, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurface, + textAlign = TextAlign.End, + modifier = Modifier.weight(1f) + ) + } +} + +@Composable +internal fun RowDivider() { + HorizontalDivider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f)) +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/result/ShareScreen.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/result/ShareScreen.kt new file mode 100644 index 0000000..906bd82 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/result/ShareScreen.kt @@ -0,0 +1,173 @@ +package org.librespeed.speedtest.ui.result + +import kotlinx.coroutines.launch +import androidx.compose.runtime.rememberCoroutineScope +import android.graphics.Bitmap +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.ContentCopy +import androidx.compose.material.icons.filled.Link +import androidx.compose.material.icons.filled.Photo +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.librespeed.speedtest.R +import org.librespeed.speedtest.data.AppPreferences +import org.librespeed.speedtest.data.HistoryDatabase +import org.librespeed.speedtest.data.HistoryEntry +import org.librespeed.speedtest.share.ShareImage +import org.librespeed.speedtest.share.ShareResult + +@Composable +fun ShareScreen(entryId: Long, onBack: () -> Unit) { + val context = LocalContext.current + val scope = rememberCoroutineScope() + val prefs = remember { AppPreferences(context.applicationContext) } + val useMBytes by prefs.useMBytes.collectAsStateWithLifecycle(initialValue = false) + var entry by remember { mutableStateOf(null) } + var missing by remember { mutableStateOf(false) } + var preview by remember { mutableStateOf(null) } + + LaunchedEffect(entryId) { + val loaded = withContext(Dispatchers.IO) { HistoryDatabase(context.applicationContext).read(entryId) } + if (loaded == null) missing = true else entry = loaded + } + LaunchedEffect(missing) { if (missing) onBack() } + LaunchedEffect(entry, useMBytes) { + entry?.let { loaded -> + preview = withContext(Dispatchers.Default) { ShareImage.render(context, loaded, useMBytes) } + } + } + + val result = entry ?: return + + fun copyText() { + ShareResult.copy( + context, + ShareResult.buildText( + context, result.server, result.download, result.upload, result.ping, + result.jitter, result.loss, useMBytes, result.shareUrl, + result.networkType, result.ipVersion + ) + ) + } + + Column( + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Row( + modifier = Modifier.fillMaxWidth().padding(start = 4.dp, end = 48.dp, top = 4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + IconButton(onClick = onBack) { + Icon(Icons.Filled.Close, contentDescription = stringResource(R.string.dialog_close)) + } + Text( + text = stringResource(R.string.share_result), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onBackground, + textAlign = TextAlign.Center, + modifier = Modifier.weight(1f) + ) + } + + Column(Modifier.widthIn(max = 560.dp).fillMaxWidth().padding(horizontal = 24.dp)) { + preview?.let { bitmap -> + Image( + bitmap = bitmap.asImageBitmap(), + contentDescription = null, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp) + .clip(RoundedCornerShape(20.dp)) + ) + } + + Spacer(Modifier.padding(top = 16.dp)) + Card(colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)) { + Column(Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 4.dp)) { + ShareOption( + icon = Icons.Filled.Photo, + title = stringResource(R.string.share_image), + subtitle = stringResource(R.string.share_image_hint) + ) { + //rendering and PNG-encoding the card takes a while; keep it off the UI thread + scope.launch(Dispatchers.Default) { ShareImage.share(context, result, useMBytes) } + } + result.shareUrl?.let { url -> + OptionDivider() + ShareOption( + icon = Icons.Filled.Link, + title = stringResource(R.string.share_link), + subtitle = stringResource(R.string.share_link_hint) + ) { ShareResult.shareLink(context, url) } + } + OptionDivider() + ShareOption( + icon = Icons.Filled.ContentCopy, + title = stringResource(R.string.share_copy), + subtitle = stringResource(R.string.share_copy_hint) + ) { copyText() } + } + } + Spacer(Modifier.padding(bottom = 20.dp)) + } + } +} + +@Composable +private fun OptionDivider() { + HorizontalDivider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f)) +} + +@Composable +private fun ShareOption(icon: ImageVector, title: String, subtitle: String, onClick: () -> Unit) { + Row( + modifier = Modifier.fillMaxWidth().clickable(onClick = onClick).padding(vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon(icon, contentDescription = null, tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(24.dp)) + Spacer(Modifier.width(14.dp)) + Column { + Text(title, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurface) + Text(subtitle, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + } + } +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/result/TestDetailsScreen.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/result/TestDetailsScreen.kt new file mode 100644 index 0000000..0443f3d --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/result/TestDetailsScreen.kt @@ -0,0 +1,184 @@ +package org.librespeed.speedtest.ui.result + +import android.os.Build +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Android +import androidx.compose.material.icons.filled.Apps +import androidx.compose.material.icons.filled.ArrowDownward +import androidx.compose.material.icons.filled.ArrowUpward +import androidx.compose.material.icons.filled.Business +import androidx.compose.material.icons.filled.CloudUpload +import androidx.compose.material.icons.filled.DataUsage +import androidx.compose.material.icons.filled.Event +import androidx.compose.material.icons.filled.Info +import androidx.compose.material.icons.filled.Lan +import androidx.compose.material.icons.filled.MyLocation +import androidx.compose.material.icons.filled.NetworkPing +import androidx.compose.material.icons.filled.Public +import androidx.compose.material.icons.filled.Schedule +import androidx.compose.material.icons.filled.Smartphone +import androidx.compose.material.icons.filled.Tag +import androidx.compose.material.icons.filled.Wifi +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.librespeed.speedtest.BuildConfig +import org.librespeed.speedtest.R +import org.librespeed.speedtest.data.GeoDistance +import org.librespeed.speedtest.data.HistoryDatabase +import org.librespeed.speedtest.data.HistoryEntry +import org.librespeed.speedtest.ui.history.formatDate +import java.util.Locale + +@Composable +fun TestDetailsScreen(entryId: Long, onBack: () -> Unit) { + val context = LocalContext.current + var entry by remember { mutableStateOf(null) } + var missing by remember { mutableStateOf(false) } + + LaunchedEffect(entryId) { + val loaded = withContext(Dispatchers.IO) { HistoryDatabase(context.applicationContext).read(entryId) } + if (loaded == null) missing = true else entry = loaded + } + LaunchedEffect(missing) { if (missing) onBack() } + + val result = entry ?: return + + Column( + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Row( + modifier = Modifier.fillMaxWidth().padding(start = 4.dp, end = 16.dp, top = 4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + IconButton(onClick = onBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(R.string.dialog_close)) + } + Text( + text = stringResource(R.string.test_details_title), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onBackground + ) + } + + Column(Modifier.widthIn(max = 560.dp).fillMaxWidth().padding(horizontal = 20.dp)) { + Section(stringResource(R.string.section_test)) { + result.shareUrl?.let { + DetailRow(stringResource(R.string.detail_result_id), it.substringAfterLast("=", it), Icons.Filled.Tag) + RowDivider() + } + DetailRow(stringResource(R.string.section_date), formatDate(result.date), Icons.Filled.Event) + if (result.durationMs > 0) { + RowDivider() + DetailRow(stringResource(R.string.detail_duration), String.format(Locale.US, "%.1f s", result.durationMs / 1000.0), Icons.Filled.Schedule) + } + } + + Section(stringResource(R.string.section_server)) { + DetailRow(stringResource(R.string.servers_add_name), GeoDistance.cleanName(result.server), Icons.Filled.Public) + GeoDistance.sponsor(result.server)?.let { + RowDivider() + DetailRow(stringResource(R.string.detail_isp), it, Icons.Filled.Business) + } + if (result.ping >= 0) { + RowDivider() + DetailRow(stringResource(R.string.info_latency), String.format(Locale.US, "%.1f %s", result.ping, stringResource(R.string.unit_ms)), Icons.Filled.NetworkPing) + } + } + + Section(stringResource(R.string.section_network)) { + if (result.ipVersion != 0) { + DetailRow(stringResource(R.string.detail_protocol), "IPv${result.ipVersion}", Icons.Filled.Lan) + RowDivider() + } + result.networkType?.let { + DetailRow(stringResource(R.string.detail_network), it, Icons.Filled.Wifi) + RowDivider() + } + result.ipInfo?.takeIf { it.isNotBlank() }?.let { info -> + val ip = info.substringBefore(" - ").trim() + val provider = info.substringAfter(" - ", "").trim() + DetailRow(stringResource(R.string.detail_ip), ip, Icons.Filled.MyLocation) + if (provider.isNotEmpty()) { + RowDivider() + DetailRow(stringResource(R.string.detail_isp), provider, Icons.Filled.Business) + } + } + } + + Section(stringResource(R.string.section_data)) { + val downloadMb = result.downloadSamples.sum() * 0.1 / 8 + val uploadMb = result.uploadSamples.sum() * 0.1 / 8 + if (downloadMb > 0) { + DetailRow(stringResource(R.string.detail_dl_data), String.format(Locale.US, "~ %.0f MB", downloadMb), Icons.Filled.ArrowDownward) + RowDivider() + } + if (uploadMb > 0) { + DetailRow(stringResource(R.string.detail_ul_data), String.format(Locale.US, "~ %.0f MB", uploadMb), Icons.Filled.ArrowUpward) + RowDivider() + } + DetailRow(stringResource(R.string.detail_data), String.format(Locale.US, "~ %.0f MB", downloadMb + uploadMb), Icons.Filled.DataUsage) + } + + Section(stringResource(R.string.section_telemetry)) { + DetailRow( + stringResource(R.string.settings_section_telemetry), + stringResource(if (result.shareUrl != null) R.string.telemetry_submitted else R.string.telemetry_not_submitted), + Icons.Filled.CloudUpload + ) + } + + Section(stringResource(R.string.section_client)) { + DetailRow(stringResource(R.string.section_application), "LibreSpeed", Icons.Filled.Apps) + RowDivider() + DetailRow(stringResource(R.string.section_version), BuildConfig.VERSION_NAME, Icons.Filled.Info) + RowDivider() + DetailRow("Android", Build.VERSION.RELEASE, Icons.Filled.Android) + RowDivider() + DetailRow(stringResource(R.string.section_device), "${Build.MANUFACTURER} ${Build.MODEL}", Icons.Filled.Smartphone) + } + Spacer(Modifier.height(20.dp)) + } + } +} + +@Composable +private fun Section(title: String, content: @Composable () -> Unit) { + Text( + text = title.uppercase(), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.fillMaxWidth().padding(top = 16.dp, bottom = 6.dp) + ) + Card(colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)) { + Column(Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 4.dp)) { content() } + } +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/servers/ServerSheet.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/servers/ServerSheet.kt new file mode 100644 index 0000000..5611b28 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/servers/ServerSheet.kt @@ -0,0 +1,259 @@ +package org.librespeed.speedtest.ui.servers + +import android.content.Intent +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material.icons.filled.Info +import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material.icons.filled.Share +import androidx.compose.material.icons.filled.Speed +import androidx.compose.material.icons.filled.Star +import androidx.compose.material.icons.outlined.StarBorder +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import com.fdossena.speedtest.core.serverSelector.TestPoint +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.librespeed.speedtest.R +import org.librespeed.speedtest.data.GeoDistance +import org.librespeed.speedtest.data.HistoryDatabase +import org.librespeed.speedtest.data.key +import org.librespeed.speedtest.ui.history.formatDate +import java.net.Inet4Address +import java.net.Inet6Address +import java.net.InetAddress + +@androidx.compose.material3.ExperimentalMaterial3Api +@Composable +fun ServerSheet( + server: TestPoint, + favorite: Boolean, + custom: Boolean, + distanceKm: Int?, + onSelect: () -> Unit, + onToggleFavorite: () -> Unit, + onPing: () -> Unit, + onDelete: () -> Unit, + onDismiss: () -> Unit +) { + val context = LocalContext.current + val host = GeoDistance.hostLabel(server.server) + var ipv4 by remember { mutableStateOf(null) } + var ipv6 by remember { mutableStateOf(null) } + var lastTest by remember { mutableStateOf(null) } + + LaunchedEffect(server.key()) { + withContext(Dispatchers.IO) { + try { + val addresses = InetAddress.getAllByName(host.substringBefore("/").substringBefore(":")) + ipv4 = addresses.firstOrNull { it is Inet4Address }?.hostAddress + ipv6 = addresses.firstOrNull { it is Inet6Address }?.hostAddress + } catch (_: Exception) { + } + lastTest = try { + HistoryDatabase(context.applicationContext).readAll() + .firstOrNull { it.server == server.name }?.date + } catch (_: Exception) { + null + } + } + } + + ModalBottomSheet(onDismissRequest = onDismiss) { + Column( + modifier = Modifier + .fillMaxWidth() + .verticalScroll(rememberScrollState()) + .padding(start = 20.dp, end = 20.dp, bottom = 24.dp) + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + Column(Modifier.weight(1f)) { + Text( + text = GeoDistance.cleanName(server.name), + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurface, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Text( + text = host, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + if (server.ping >= 0) { + Text( + text = "${server.ping.toInt()} ${stringResource(R.string.unit_ms)}", + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary + ) + } + IconButton(onClick = onToggleFavorite) { + Icon( + imageVector = if (favorite) Icons.Filled.Star else Icons.Outlined.StarBorder, + contentDescription = stringResource(R.string.servers_favorite), + tint = if (favorite) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + HorizontalDivider(Modifier.padding(vertical = 10.dp), color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f)) + + SheetAction( + icon = Icons.Filled.PlayArrow, + title = stringResource(R.string.sheet_select), + subtitle = stringResource(R.string.sheet_select_hint), + onClick = onSelect + ) + if (!favorite) { + SheetAction( + icon = Icons.Outlined.StarBorder, + title = stringResource(R.string.sheet_favorite), + subtitle = stringResource(R.string.sheet_favorite_hint), + onClick = onToggleFavorite + ) + } + SheetAction( + icon = Icons.Filled.Info, + title = stringResource(R.string.sheet_info), + subtitle = stringResource(R.string.sheet_info_hint), + onClick = null + ) + Card(colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceContainerHigh)) { + Column(Modifier.fillMaxWidth().padding(horizontal = 14.dp, vertical = 6.dp)) { + InfoRow(stringResource(R.string.info_location), GeoDistance.cleanName(server.name)) + GeoDistance.sponsor(server.name)?.let { InfoRow(stringResource(R.string.detail_isp), it) } + InfoRow(stringResource(R.string.detail_server), host) + distanceKm?.let { InfoRow(stringResource(R.string.info_distance), "~ $it km") } + if (server.ping >= 0) InfoRow(stringResource(R.string.info_latency), "${server.ping.toInt()} ${stringResource(R.string.unit_ms)}") + ipv4?.let { InfoRow("IPv4", it) } + ipv6?.let { InfoRow("IPv6", it) } + lastTest?.let { InfoRow(stringResource(R.string.info_last_test), formatDate(it)) } + } + } + SheetAction( + icon = Icons.Filled.Speed, + title = stringResource(R.string.sheet_ping), + subtitle = stringResource(R.string.sheet_ping_hint), + onClick = onPing + ) + val shareTitle = stringResource(R.string.sheet_share) + val shareText = stringResource(R.string.share_server_text, GeoDistance.cleanName(server.name), server.server) + SheetAction( + icon = Icons.Filled.Share, + title = shareTitle, + subtitle = stringResource(R.string.sheet_share_hint), + onClick = { + val intent = Intent(Intent.ACTION_SEND).apply { + type = "text/plain" + putExtra(Intent.EXTRA_TEXT, shareText) + } + try { + context.startActivity(Intent.createChooser(intent, shareTitle)) + } catch (_: Exception) { + } + } + ) + if (favorite) { + SheetAction( + icon = Icons.Filled.Delete, + title = stringResource(R.string.sheet_unfavorite), + subtitle = stringResource(R.string.sheet_unfavorite_hint), + tint = FavoriteRed, + onClick = onToggleFavorite + ) + } + if (custom) { + SheetAction( + icon = Icons.Filled.Delete, + title = stringResource(R.string.servers_delete), + subtitle = stringResource(R.string.sheet_delete_hint), + tint = FavoriteRed, + onClick = onDelete + ) + } + } + } +} + +private val FavoriteRed = Color(0xFFEF4444) + +@Composable +private fun SheetAction( + icon: ImageVector, + title: String, + subtitle: String, + tint: Color = MaterialTheme.colorScheme.primary, + onClick: (() -> Unit)? +) { + val rowModifier = if (onClick != null) { + Modifier.fillMaxWidth().clickable(onClick = onClick).padding(vertical = 10.dp) + } else { + Modifier.fillMaxWidth().padding(vertical = 10.dp) + } + Row(rowModifier, verticalAlignment = Alignment.CenterVertically) { + Icon(icon, contentDescription = null, tint = tint, modifier = Modifier.size(24.dp)) + Spacer(Modifier.width(14.dp)) + Column { + Text( + text = title, + style = MaterialTheme.typography.bodyLarge, + color = if (tint == FavoriteRed) tint else MaterialTheme.colorScheme.onSurface + ) + Text( + text = subtitle, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } +} + +@Composable +private fun InfoRow(title: String, value: String) { + Row(Modifier.fillMaxWidth().padding(vertical = 6.dp), verticalAlignment = Alignment.CenterVertically) { + Text( + text = title, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.width(130.dp) + ) + Text( + text = value, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface + ) + } +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/servers/ServersScreen.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/servers/ServersScreen.kt new file mode 100644 index 0000000..6e304c6 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/servers/ServersScreen.kt @@ -0,0 +1,357 @@ +package org.librespeed.speedtest.ui.servers + +import android.Manifest +import android.content.pm.PackageManager +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material.icons.filled.Public +import androidx.compose.material.icons.filled.Refresh +import androidx.compose.material.icons.filled.Star +import androidx.compose.material.icons.outlined.StarBorder +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Tab +import androidx.compose.material3.TabRow +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.fdossena.speedtest.core.serverSelector.TestPoint +import org.librespeed.speedtest.R +import org.librespeed.speedtest.data.GeoDistance +import org.librespeed.speedtest.data.key +import org.librespeed.speedtest.ui.speedtest.SpeedtestViewModel +import org.librespeed.speedtest.ui.theme.DangerRed +import org.librespeed.speedtest.ui.theme.Teal + +private val Amber = Color(0xFFF7941D) + +@androidx.compose.material3.ExperimentalMaterial3Api +@Composable +fun ServersScreen(viewModel: SpeedtestViewModel) { + val state by viewModel.state.collectAsStateWithLifecycle() + val context = LocalContext.current + //start on All servers when there are no favorites yet + var tabOverride by remember { mutableIntStateOf(-1) } + val tab = if (tabOverride != -1) tabOverride else if (state.favorites.isEmpty()) 1 else 0 + var showAddDialog by remember { mutableStateOf(false) } + var sheetServer by remember { mutableStateOf(null) } + var hasLocation by remember { + mutableStateOf( + ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == + PackageManager.PERMISSION_GRANTED + ) + } + val locationLauncher = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { granted -> + hasLocation = granted + if (granted) viewModel.computeDistances() + } + + val sorted = remember(state.servers, state.customKeys) { + state.servers + .filter { it.ping >= 0 || it.key() in state.customKeys } + .sortedBy { if (it.ping < 0) Float.MAX_VALUE else it.ping } + } + val visible = if (tab == 0) sorted.filter { it.key() in state.favorites } else sorted + + Column(Modifier.fillMaxSize()) { + Row( + modifier = Modifier.fillMaxWidth().padding(start = 20.dp, end = 8.dp, top = 8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(R.string.nav_servers), + style = MaterialTheme.typography.headlineSmall, + color = MaterialTheme.colorScheme.onBackground, + modifier = Modifier.weight(1f) + ) + IconButton(onClick = { showAddDialog = true }) { + Icon(Icons.Filled.Add, contentDescription = stringResource(R.string.servers_add)) + } + IconButton(onClick = { viewModel.refreshServers() }, enabled = !state.selectingServers) { + if (state.selectingServers) { + CircularProgressIndicator(modifier = Modifier.size(20.dp), strokeWidth = 2.dp) + } else { + Icon(Icons.Filled.Refresh, contentDescription = stringResource(R.string.servers_refresh)) + } + } + } + Card( + onClick = { viewModel.useAutoSelect() }, + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), + border = if (!state.pinnedServer) BorderStroke(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.7f)) else null, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp) + ) { + Row( + modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + Icons.Filled.Public, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(20.dp) + ) + Spacer(Modifier.width(12.dp)) + Column(Modifier.weight(1f)) { + Text( + text = stringResource(R.string.server_auto_select), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface + ) + if (!state.pinnedServer && state.selectedServer != null) { + Text( + text = GeoDistance.cleanName(state.selectedServer!!.name), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + } + if (!state.pinnedServer) { + Icon( + Icons.Filled.Check, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary + ) + } + } + } + if (!hasLocation) { + TextButton( + onClick = { locationLauncher.launch(Manifest.permission.ACCESS_COARSE_LOCATION) }, + modifier = Modifier.padding(horizontal = 8.dp) + ) { + Text(stringResource(R.string.servers_show_distances)) + } + } + TabRow(selectedTabIndex = tab, containerColor = MaterialTheme.colorScheme.background) { + Tab(selected = tab == 0, onClick = { tabOverride = 0 }, text = { Text(stringResource(R.string.servers_favorites)) }) + Tab(selected = tab == 1, onClick = { tabOverride = 1 }, text = { Text(stringResource(R.string.servers_all)) }) + } + if (visible.isEmpty()) { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Text( + text = stringResource(if (tab == 0) R.string.servers_no_favorites else R.string.servers_none), + color = MaterialTheme.colorScheme.onSurfaceVariant, + style = MaterialTheme.typography.bodyMedium + ) + } + } else { + LazyColumn(Modifier.fillMaxSize(), contentPadding = PaddingValues(16.dp)) { + items(visible, key = { it.key() }) { server -> + ServerRow( + server = server, + selected = state.pinnedServer && state.selectedServer?.key() == server.key(), + favorite = server.key() in state.favorites, + distanceKm = state.distances[server.key()], + onClick = { viewModel.selectServer(server) }, + onToggleFavorite = { viewModel.toggleFavorite(server) }, + onMore = { sheetServer = server } + ) + Spacer(Modifier.height(8.dp)) + } + } + } + } + + sheetServer?.let { server -> + ServerSheet( + server = server, + favorite = server.key() in state.favorites, + custom = server.key() in state.customKeys, + distanceKm = state.distances[server.key()], + onSelect = { + viewModel.selectServer(server) + sheetServer = null + }, + onToggleFavorite = { viewModel.toggleFavorite(server) }, + onPing = { viewModel.pingServer(server) }, + onDelete = { + viewModel.removeCustomServer(server) + sheetServer = null + }, + onDismiss = { sheetServer = null } + ) + } + + if (showAddDialog) { + AddServerDialog( + onDismiss = { showAddDialog = false }, + onAdd = { name, url -> + if (viewModel.addCustomServer(name, url)) { + showAddDialog = false + true + } else false + } + ) + } +} + +private fun latencyColor(ping: Float): Color = when { + ping < 50 -> Teal + ping < 150 -> Amber + else -> DangerRed +} + +@Composable +private fun ServerRow( + server: TestPoint, + selected: Boolean, + favorite: Boolean, + distanceKm: Int?, + onClick: () -> Unit, + onToggleFavorite: () -> Unit, + onMore: () -> Unit +) { + Card( + onClick = onClick, + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), + border = if (selected) BorderStroke(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.7f)) else null, + modifier = Modifier.fillMaxWidth() + ) { + Row( + modifier = Modifier.padding(start = 16.dp, end = 4.dp, top = 8.dp, bottom = 8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Column(Modifier.weight(1f)) { + Text( + text = GeoDistance.cleanName(server.name), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Text( + text = GeoDistance.hostLabel(server.server), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + Column(horizontalAlignment = Alignment.End) { + if (server.ping >= 0) { + Text( + text = "${server.ping.toInt()} ${stringResource(R.string.unit_ms)}", + style = MaterialTheme.typography.labelMedium, + color = latencyColor(server.ping) + ) + } else { + Text( + text = stringResource(R.string.servers_unreachable), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.error + ) + } + distanceKm?.let { + Text( + text = "$it km", + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + IconButton(onClick = onToggleFavorite) { + Icon( + imageVector = if (favorite) Icons.Filled.Star else Icons.Outlined.StarBorder, + contentDescription = stringResource(R.string.servers_favorite), + tint = if (favorite) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant + ) + } + IconButton(onClick = onMore) { + Icon( + Icons.Filled.MoreVert, + contentDescription = stringResource(R.string.servers_details), + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + } +} + +@Composable +private fun AddServerDialog(onDismiss: () -> Unit, onAdd: (String, String) -> Boolean) { + var name by remember { mutableStateOf("") } + var url by remember { mutableStateOf("") } + var failed by remember { mutableStateOf(false) } + + AlertDialog( + onDismissRequest = onDismiss, + title = { Text(stringResource(R.string.servers_add)) }, + text = { + Column { + OutlinedTextField( + value = name, + onValueChange = { name = it }, + singleLine = true, + label = { Text(stringResource(R.string.servers_add_name)) } + ) + Spacer(Modifier.height(10.dp)) + OutlinedTextField( + value = url, + onValueChange = { url = it }, + singleLine = true, + label = { Text(stringResource(R.string.servers_add_url)) }, + placeholder = { Text("https://speedtest.example.com/backend") }, + isError = failed + ) + Spacer(Modifier.height(6.dp)) + Text( + text = stringResource(if (failed) R.string.servers_add_invalid else R.string.servers_add_hint), + style = MaterialTheme.typography.bodySmall, + color = if (failed) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurfaceVariant + ) + } + }, + confirmButton = { + TextButton( + enabled = name.isNotBlank() && url.isNotBlank(), + onClick = { failed = !onAdd(name, url) } + ) { Text(stringResource(R.string.servers_add_confirm)) } + }, + dismissButton = { + TextButton(onClick = onDismiss) { Text(stringResource(R.string.dialog_cancel)) } + } + ) +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/settings/SettingsScreen.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/settings/SettingsScreen.kt new file mode 100644 index 0000000..389d35e --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/settings/SettingsScreen.kt @@ -0,0 +1,335 @@ +package org.librespeed.speedtest.ui.settings + +import android.content.Intent +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ChevronRight +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.RadioButton +import androidx.compose.material3.Switch +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.dp +import androidx.core.net.toUri +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlinx.coroutines.launch +import org.librespeed.speedtest.R +import org.librespeed.speedtest.data.AppPreferences +import org.librespeed.speedtest.data.ClientInfo + +private const val PROJECT_URL = "https://github.com/librespeed/speedtest-android" +private const val WEBSITE_URL = "https://librespeed.org" + +@Composable +fun SettingsScreen( + serverLabel: String?, + serverPinned: Boolean, + onServersClick: () -> Unit +) { + val context = LocalContext.current + val prefs = remember { AppPreferences(context.applicationContext) } + val scope = rememberCoroutineScope() + + val themeMode by prefs.themeMode.collectAsStateWithLifecycle(initialValue = "system") + val useMBytes by prefs.useMBytes.collectAsStateWithLifecycle(initialValue = false) + val telemetry by prefs.telemetryEnabled.collectAsStateWithLifecycle(initialValue = false) + val singleConnection by prefs.singleConnection.collectAsStateWithLifecycle(initialValue = false) + + var unitsDialog by remember { mutableStateOf(false) } + var themeDialog by remember { mutableStateOf(false) } + var testModeDialog by remember { mutableStateOf(false) } + var whatIsSentDialog by remember { mutableStateOf(false) } + + Column( + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 20.dp) + ) { + Spacer(Modifier.height(8.dp)) + Text( + text = stringResource(R.string.nav_settings), + style = MaterialTheme.typography.headlineSmall, + color = MaterialTheme.colorScheme.onBackground + ) + SectionTitle(stringResource(R.string.settings_section_general)) + SettingsCard { + ValueRow( + title = stringResource(R.string.settings_server), + value = when { + serverPinned && serverLabel != null -> serverLabel + else -> stringResource(R.string.server_auto_select) + }, + onClick = onServersClick + ) + RowDivider() + ValueRow( + title = stringResource(R.string.settings_units), + value = stringResource(if (useMBytes) R.string.unit_mbytes else R.string.unit_mbps), + onClick = { unitsDialog = true } + ) + RowDivider() + ValueRow( + title = stringResource(R.string.settings_theme), + value = stringResource( + when (themeMode) { + "light" -> R.string.theme_light + "dark" -> R.string.theme_dark + else -> R.string.theme_system + } + ), + onClick = { themeDialog = true } + ) + RowDivider() + ValueRow( + title = stringResource(R.string.settings_test_mode), + value = stringResource(if (singleConnection) R.string.test_mode_single else R.string.test_mode_standard), + onClick = { testModeDialog = true } + ) + } + SectionTitle(stringResource(R.string.settings_section_telemetry)) + SettingsCard { + Row(verticalAlignment = Alignment.CenterVertically) { + Column(Modifier.weight(1f)) { + Text( + text = stringResource(R.string.settings_telemetry), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = stringResource(R.string.settings_telemetry_summary), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Switch( + checked = telemetry, + onCheckedChange = { checked -> scope.launch { prefs.setTelemetryEnabled(checked) } } + ) + } + Text( + text = stringResource(R.string.settings_whats_sent), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier + .clickable(onClick = { whatIsSentDialog = true }, role = Role.Button) + .padding(top = 10.dp, bottom = 2.dp) + ) + } + SectionTitle(stringResource(R.string.settings_section_about)) + SettingsCard { + Column(Modifier.padding(vertical = 10.dp)) { + Text( + text = ClientInfo.client, + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = stringResource(R.string.settings_license), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + RowDivider() + NavRow(stringResource(R.string.settings_licenses)) { context.openUrl("$PROJECT_URL/blob/master/LICENSE") } + RowDivider() + NavRow(stringResource(R.string.settings_source)) { context.openUrl(PROJECT_URL) } + RowDivider() + NavRow(stringResource(R.string.settings_website)) { context.openUrl(WEBSITE_URL) } + RowDivider() + NavRow(stringResource(R.string.settings_privacy)) { context.openUrl("$PROJECT_URL/blob/master/PRIVACY.md") } + } + Spacer(Modifier.height(16.dp)) + } + + if (unitsDialog) { + RadioDialog( + title = stringResource(R.string.settings_units), + options = listOf( + stringResource(R.string.unit_mbps_long) to !useMBytes, + stringResource(R.string.unit_mbytes_long) to useMBytes + ), + hint = stringResource(R.string.settings_units_hint), + onSelect = { index -> scope.launch { prefs.setUseMBytes(index == 1) } }, + onDismiss = { unitsDialog = false } + ) + } + if (themeDialog) { + RadioDialog( + title = stringResource(R.string.settings_theme), + options = listOf( + stringResource(R.string.theme_system) to (themeMode == "system"), + stringResource(R.string.theme_light) to (themeMode == "light"), + stringResource(R.string.theme_dark) to (themeMode == "dark") + ), + hint = null, + onSelect = { index -> + scope.launch { prefs.setThemeMode(listOf("system", "light", "dark")[index]) } + }, + onDismiss = { themeDialog = false } + ) + } + if (testModeDialog) { + RadioDialog( + title = stringResource(R.string.settings_test_mode), + options = listOf( + stringResource(R.string.test_mode_standard) to !singleConnection, + stringResource(R.string.test_mode_single) to singleConnection + ), + hint = stringResource(R.string.test_mode_hint), + onSelect = { index -> scope.launch { prefs.setSingleConnection(index == 1) } }, + onDismiss = { testModeDialog = false } + ) + } + if (whatIsSentDialog) { + AlertDialog( + onDismissRequest = { whatIsSentDialog = false }, + title = { Text(stringResource(R.string.settings_whats_sent)) }, + text = { Text(stringResource(R.string.settings_telemetry_detail)) }, + confirmButton = { + TextButton(onClick = { whatIsSentDialog = false }) { Text(stringResource(R.string.dialog_close)) } + } + ) + } +} + +private fun android.content.Context.openUrl(url: String) { + try { + startActivity(Intent(Intent.ACTION_VIEW, url.toUri())) + } catch (_: Exception) { + } +} + +@Composable +private fun SectionTitle(text: String) { + Text( + text = text.uppercase(), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.padding(top = 20.dp, bottom = 8.dp) + ) +} + +@Composable +private fun SettingsCard(content: @Composable () -> Unit) { + Card(colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)) { + Column(Modifier.fillMaxWidth().padding(16.dp)) { content() } + } +} + +@Composable +private fun ValueRow(title: String, value: String, onClick: () -> Unit) { + Row( + modifier = Modifier.fillMaxWidth().clickable(onClick = onClick, role = Role.Button).padding(vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Column(Modifier.weight(1f)) { + Text( + text = title, + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = value, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Icon( + Icons.Filled.ChevronRight, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } +} + +@Composable +private fun RowDivider() { + HorizontalDivider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.2f)) +} + +@Composable +private fun NavRow(label: String, onClick: () -> Unit) { + Row( + modifier = Modifier.fillMaxWidth().clickable(onClick = onClick, role = Role.Button).padding(vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = label, + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.weight(1f) + ) + Icon( + Icons.Filled.ChevronRight, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } +} + +@Composable +private fun RadioDialog( + title: String, + options: List>, + hint: String?, + onSelect: (Int) -> Unit, + onDismiss: () -> Unit +) { + AlertDialog( + onDismissRequest = onDismiss, + title = { Text(title) }, + text = { + Column { + options.forEachIndexed { index, (label, selected) -> + Row( + modifier = Modifier.fillMaxWidth().clickable { + onSelect(index) + onDismiss() + }, + verticalAlignment = Alignment.CenterVertically + ) { + RadioButton(selected = selected, onClick = { + onSelect(index) + onDismiss() + }) + Text(label, style = MaterialTheme.typography.bodyMedium) + } + } + hint?.let { + Text( + text = it, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 8.dp) + ) + } + } + }, + confirmButton = { + TextButton(onClick = onDismiss) { Text(stringResource(R.string.dialog_close)) } + } + ) +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/speedtest/SpeedtestScreen.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/speedtest/SpeedtestScreen.kt new file mode 100644 index 0000000..edd7ae5 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/speedtest/SpeedtestScreen.kt @@ -0,0 +1,392 @@ +package org.librespeed.speedtest.ui.speedtest + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDownward +import androidx.compose.material.icons.filled.ArrowUpward +import androidx.compose.material.icons.filled.ChevronRight +import androidx.compose.material.icons.filled.NetworkPing +import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material.icons.filled.Public +import androidx.compose.material.icons.filled.Refresh +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material.icons.filled.Stop +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.librespeed.speedtest.R +import org.librespeed.speedtest.ui.components.SpeedGauge +import org.librespeed.speedtest.ui.components.Sparkline +import org.librespeed.speedtest.ui.theme.Purple +import org.librespeed.speedtest.ui.theme.Teal +import java.util.Locale + +@Composable +fun SpeedtestScreen( + viewModel: SpeedtestViewModel, + onServersClick: () -> Unit, + onSettingsClick: () -> Unit, + onResult: (Long) -> Unit +) { + val state by viewModel.state.collectAsStateWithLifecycle() + val resultId by viewModel.lastResultId.collectAsStateWithLifecycle() + val unitLabel = stringResource(if (state.useMBytes) R.string.unit_mbytes else R.string.unit_mbps) + fun display(value: Double): Double = if (state.useMBytes) value / 8 else value + + LaunchedEffect(resultId) { + resultId?.let { + viewModel.consumeResult() + onResult(it) + } + } + + Column( + modifier = Modifier.fillMaxSize().padding(horizontal = 20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box(modifier = Modifier.widthIn(max = 500.dp).fillMaxWidth()) { + Row( + modifier = Modifier.align(Alignment.Center), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.ic_logo), + contentDescription = null, + modifier = Modifier.size(28.dp) + ) + Spacer(Modifier.width(8.dp)) + Text( + text = buildAnnotatedString { + withStyle(SpanStyle(color = MaterialTheme.colorScheme.primary)) { append("Libre") } + withStyle(SpanStyle(color = MaterialTheme.colorScheme.onBackground)) { append("Speed") } + }, + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.Bold + ) + } + IconButton( + onClick = onSettingsClick, + modifier = Modifier.align(Alignment.CenterEnd) + ) { + Icon( + Icons.Filled.Settings, + contentDescription = stringResource(R.string.nav_settings), + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + Spacer(Modifier.height(6.dp)) + ServerChip( + state = state, + onClick = { + if (state.serverListFailed) viewModel.refreshServers() else onServersClick() + } + ) + + Spacer(Modifier.weight(1f)) + SpeedGauge( + speed = state.currentSpeed, + modifier = Modifier.widthIn(max = 384.dp).fillMaxWidth() + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Text( + text = if (state.phase == Phase.IDLE || state.phase == Phase.ERROR) "—" + else String.format(Locale.US, "%.2f", display(state.currentSpeed)), + style = MaterialTheme.typography.displaySmall, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.onBackground + ) + Text( + text = unitLabel, + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(Modifier.height(4.dp)) + PhaseLabel(state) + } + } + + Spacer(Modifier.weight(1f)) + Row(modifier = Modifier.widthIn(max = 500.dp).fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp)) { + MetricCard( + modifier = Modifier.weight(1f), + title = stringResource(R.string.test_download), + icon = { Icon(Icons.Filled.ArrowDownward, null, tint = Teal, modifier = Modifier.size(16.dp)) }, + value = if (state.download < 0) state.download else display(state.download), + unit = unitLabel, + accent = Teal, + samples = state.downloadSamples + ) + MetricCard( + modifier = Modifier.weight(1f), + title = stringResource(R.string.test_upload), + icon = { Icon(Icons.Filled.ArrowUpward, null, tint = Purple, modifier = Modifier.size(16.dp)) }, + value = if (state.upload < 0) state.upload else display(state.upload), + unit = unitLabel, + accent = Purple, + samples = state.uploadSamples + ) + } + + Spacer(Modifier.height(10.dp)) + Row(modifier = Modifier.widthIn(max = 500.dp).fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp)) { + SmallMetric(Modifier.weight(1f), stringResource(R.string.test_ping), state.ping, stringResource(R.string.unit_ms)) + SmallMetric(Modifier.weight(1f), stringResource(R.string.test_jitter), state.jitter, stringResource(R.string.unit_ms)) + SmallMetric(Modifier.weight(1f), stringResource(R.string.test_loss), state.loss, "%") + } + + Spacer(Modifier.height(14.dp)) + val running = state.phase in setOf(Phase.PING, Phase.DOWNLOAD, Phase.UPLOAD) + OutlinedButton( + onClick = { viewModel.startOrStop() }, + enabled = state.selectedServer != null || state.phase != Phase.IDLE, + border = BorderStroke(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.6f)), + colors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.colorScheme.primary), + modifier = Modifier.widthIn(max = 500.dp).fillMaxWidth().height(52.dp) + ) { + Icon( + imageVector = if (running) Icons.Filled.Stop else Icons.Filled.PlayArrow, + contentDescription = null, + modifier = Modifier.size(20.dp) + ) + Spacer(Modifier.width(8.dp)) + Text( + text = stringResource( + when { + running -> R.string.test_stop + state.phase == Phase.ERROR -> R.string.test_restart + else -> R.string.test_start + } + ), + style = MaterialTheme.typography.titleMedium + ) + } + + if (state.phase == Phase.ERROR) { + Spacer(Modifier.height(8.dp)) + Text( + text = state.error ?: stringResource(R.string.test_failed), + color = MaterialTheme.colorScheme.error, + style = MaterialTheme.typography.bodySmall, + textAlign = TextAlign.Center + ) + } + Spacer(Modifier.height(12.dp)) + } +} + +@Composable +private fun ServerChip(state: SpeedtestUiState, onClick: () -> Unit) { + Card( + onClick = onClick, + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), + modifier = Modifier.widthIn(max = 500.dp).fillMaxWidth() + ) { + Row( + modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = Icons.Filled.Public, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(20.dp) + ) + Spacer(Modifier.width(12.dp)) + Column(Modifier.weight(1f)) { + when { + //a remembered server is shown straight away; the spinner on the + //right says the rest of the list is still being pinged + state.selectingServers && state.selectedServer == null -> Text( + text = stringResource(R.string.servers_selecting), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + state.serverListFailed -> Text( + text = stringResource(R.string.servers_load_failed), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.error + ) + state.selectedServer != null -> { + Text( + text = stringResource( + if (state.pinnedServer) R.string.server_selected else R.string.server_auto_select + ), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = state.selectedServer.name, + style = MaterialTheme.typography.labelSmall, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + else -> Text( + text = stringResource(R.string.servers_none), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.error + ) + } + } + if (state.selectingServers) { + CircularProgressIndicator(modifier = Modifier.size(18.dp), strokeWidth = 2.dp) + } else if (state.serverListFailed) { + Icon(Icons.Filled.Refresh, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant) + } else { + state.selectedServer?.takeIf { it.ping >= 0 }?.let { + Text( + text = "${it.ping.toInt()} ${stringResource(R.string.unit_ms)}", + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.primary + ) + } + Spacer(Modifier.width(6.dp)) + Icon( + Icons.Filled.ChevronRight, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + } +} + +@Composable +private fun PhaseLabel(state: SpeedtestUiState) { + val text = when (state.phase) { + Phase.PING -> stringResource(R.string.phase_ping) + Phase.DOWNLOAD -> stringResource(R.string.phase_download) + Phase.UPLOAD -> stringResource(R.string.phase_upload) + else -> "" + } + if (text.isNotEmpty()) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + when (state.phase) { + Phase.DOWNLOAD -> Icon(Icons.Filled.ArrowDownward, null, tint = Teal, modifier = Modifier.size(20.dp)) + Phase.UPLOAD -> Icon(Icons.Filled.ArrowUpward, null, tint = Purple, modifier = Modifier.size(20.dp)) + else -> Icon(Icons.Filled.NetworkPing, null, tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(20.dp)) + } + Spacer(Modifier.height(4.dp)) + Text( + text = text, + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.primary + ) + } + } +} + +@Composable +private fun MetricCard( + modifier: Modifier, + title: String, + icon: @Composable () -> Unit, + value: Double, + unit: String, + accent: Color, + samples: List +) { + Card( + modifier = modifier, + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface) + ) { + Column(Modifier.padding(12.dp)) { + Row(verticalAlignment = Alignment.CenterVertically) { + icon() + Spacer(Modifier.width(6.dp)) + Text( + text = title.uppercase(Locale.ROOT), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Spacer(Modifier.height(4.dp)) + Text( + text = if (value < 0) "—" else String.format(Locale.US, "%.2f", value), + style = MaterialTheme.typography.headlineSmall, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = unit, + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Sparkline( + data = samples, + color = accent, + modifier = Modifier.fillMaxWidth().height(30.dp).padding(top = 4.dp) + ) + } + } +} + +@Composable +private fun SmallMetric(modifier: Modifier, title: String, value: Double, unit: String) { + Card( + modifier = modifier, + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface) + ) { + Column(Modifier.padding(10.dp), horizontalAlignment = Alignment.CenterHorizontally) { + Text( + text = title, + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(Modifier.height(2.dp)) + Row(verticalAlignment = Alignment.Bottom) { + Text( + text = if (value < 0) "—" else String.format(Locale.US, "%.1f", value), + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colorScheme.primary + ) + Spacer(Modifier.width(4.dp)) + Text( + text = unit, + modifier = Modifier.padding(bottom = 2.dp), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + } +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/speedtest/SpeedtestViewModel.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/speedtest/SpeedtestViewModel.kt new file mode 100644 index 0000000..62c7fa1 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/speedtest/SpeedtestViewModel.kt @@ -0,0 +1,357 @@ +package org.librespeed.speedtest.ui.speedtest + +import android.Manifest +import android.app.Application +import android.content.Context +import android.content.pm.PackageManager +import android.location.Geocoder +import android.location.Location +import android.location.LocationManager +import androidx.core.content.ContextCompat +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.viewModelScope +import com.fdossena.speedtest.core.Speedtest +import com.fdossena.speedtest.core.serverSelector.ServerSelector +import com.fdossena.speedtest.core.serverSelector.TestPoint +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.librespeed.speedtest.data.AppPreferences +import org.librespeed.speedtest.data.CustomServerFactory +import org.librespeed.speedtest.data.GeoDistance +import org.librespeed.speedtest.data.HistoryDatabase +import org.librespeed.speedtest.data.HistoryEntry +import org.librespeed.speedtest.data.NetworkInfo +import org.librespeed.speedtest.data.key +import org.librespeed.speedtest.engine.TestEngine +import kotlin.math.roundToInt + +enum class Phase { IDLE, PING, DOWNLOAD, UPLOAD, ERROR } + +data class SpeedtestUiState( + val phase: Phase = Phase.IDLE, + val selectingServers: Boolean = false, + val serverListFailed: Boolean = false, + val servers: List = emptyList(), + val selectedServer: TestPoint? = null, + val pinnedServer: Boolean = false, + val currentSpeed: Double = 0.0, + val download: Double = -1.0, + val upload: Double = -1.0, + val ping: Double = -1.0, + val jitter: Double = -1.0, + val loss: Double = -1.0, + val downloadSamples: List = emptyList(), + val uploadSamples: List = emptyList(), + val ipInfo: String? = null, + val shareUrl: String? = null, + val error: String? = null, + val favorites: Set = emptySet(), + val customKeys: Set = emptySet(), + val useMBytes: Boolean = false, + val distances: Map = emptyMap() +) + +class SpeedtestViewModel(application: Application) : AndroidViewModel(application) { + + private val engine = TestEngine(application) + private val prefs = AppPreferences(application) + private val history = HistoryDatabase(application) + private val _state = MutableStateFlow(SpeedtestUiState()) + val state: StateFlow = _state + + /** Id of the freshly saved result; the UI navigates to it and calls [consumeResult]. */ + val lastResultId = MutableStateFlow(null) + + private var telemetryEnabled = false + private var singleConnection = false + private var autoSelected: TestPoint? = null + private var discoveryJob: Job? = null + private var aborted = false + + init { + viewModelScope.launch { + prefs.favorites.collect { favorites -> _state.update { it.copy(favorites = favorites) } } + } + viewModelScope.launch { + prefs.useMBytes.collect { useMBytes -> _state.update { it.copy(useMBytes = useMBytes) } } + } + viewModelScope.launch { prefs.telemetryEnabled.collect { telemetryEnabled = it } } + viewModelScope.launch { prefs.singleConnection.collect { singleConnection = it } } + refreshServers() + } + + fun consumeResult() { + lastResultId.value = null + } + + fun refreshServers() { + if (_state.value.selectingServers) return + _state.update { it.copy(selectingServers = true, serverListFailed = false) } + discoveryJob = viewModelScope.launch { + try { + val custom = prefs.customServers.first() + val rememberedKey = prefs.rememberedServer.first() + val discovery = engine.discover(custom) { servers -> + //a remembered server is usable as soon as the list is in; pinging + //everything only refines the automatic choice, so Start need not wait + val match = rememberedKey?.let { key -> servers.find { it.key() == key } } ?: return@discover + _state.update { it.copy(servers = servers, selectedServer = match, pinnedServer = true) } + } + autoSelected = discovery.selected + val remembered = rememberedKey + ?.let { key -> discovery.servers.find { it.key() == key && it.ping >= 0 } } + _state.update { + it.copy( + selectingServers = false, + servers = discovery.servers, + //a test already running against the remembered server keeps its label + selectedServer = if (isRunning()) it.selectedServer else remembered ?: discovery.selected, + pinnedServer = remembered != null, + customKeys = custom.map { c -> c.key() }.toSet(), + serverListFailed = discovery.selected == null && discovery.servers.isEmpty() + ) + } + } catch (_: CancellationException) { + //a test started on the remembered server; the rest of the list stays unpinged + _state.update { it.copy(selectingServers = false) } + } catch (_: Exception) { + _state.update { it.copy(selectingServers = false, serverListFailed = true) } + } + computeDistances() + } + } + + /** Fills in distances to servers when coarse location is granted; results stay on the device. */ + fun computeDistances() { + viewModelScope.launch(Dispatchers.IO) { + val app = getApplication() + if (ContextCompat.checkSelfPermission(app, Manifest.permission.ACCESS_COARSE_LOCATION) + != PackageManager.PERMISSION_GRANTED + ) return@launch + val location = lastKnownLocation(app) ?: return@launch + if (!Geocoder.isPresent()) return@launch + val geocoder = Geocoder(app) + val cache = prefs.getGeoCache().toMutableMap() + for (server in _state.value.servers) { + val place = GeoDistance.cleanName(server.name) + val coordinates = cache[place] ?: try { + @Suppress("DEPRECATION") + geocoder.getFromLocationName(place, 1)?.firstOrNull() + ?.let { it.latitude to it.longitude } + ?.also { + cache[place] = it + prefs.putGeoCache(place, it.first, it.second) + } + } catch (_: Exception) { + null + } ?: continue + val km = GeoDistance.km(location.latitude, location.longitude, coordinates.first, coordinates.second) + _state.update { + it.copy(distances = it.distances + (server.key() to km.roundToInt())) + } + } + } + } + + //only called after computeDistances verified ACCESS_COARSE_LOCATION + @android.annotation.SuppressLint("MissingPermission") + private fun lastKnownLocation(app: Application): Location? = try { + val manager = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager + manager.getProviders(true) + .mapNotNull { provider -> runCatching { manager.getLastKnownLocation(provider) }.getOrNull() } + .maxByOrNull { it.time } + } catch (_: Exception) { + null + } + + fun selectServer(testPoint: TestPoint) { + if (isRunning()) return + _state.update { it.copy(selectedServer = testPoint, pinnedServer = true) } + viewModelScope.launch { prefs.setRememberedServer(testPoint.key()) } + } + + /** Returns to automatic server selection. */ + fun useAutoSelect() { + if (isRunning()) return + _state.update { it.copy(selectedServer = autoSelected ?: it.selectedServer, pinnedServer = false) } + viewModelScope.launch { prefs.setRememberedServer(null) } + } + + fun toggleFavorite(testPoint: TestPoint) { + viewModelScope.launch { prefs.toggleFavorite(testPoint.key()) } + } + + /** Re-pings a single server and refreshes the list when done. */ + fun pingServer(testPoint: TestPoint) { + viewModelScope.launch(Dispatchers.IO) { + try { + object : ServerSelector(arrayOf(testPoint), 2000) { + override fun onServerSelected(server: TestPoint?) { + _state.update { it.copy(servers = it.servers.toList()) } + } + }.start() + } catch (_: Exception) { + } + } + } + + /** Returns false when the URL is invalid. */ + fun addCustomServer(name: String, url: String): Boolean { + val testPoint = try { + CustomServerFactory.create(name, url) + } catch (_: Exception) { + return false + } + viewModelScope.launch { + prefs.addCustomServer(testPoint) + refreshServers() + } + return true + } + + fun removeCustomServer(testPoint: TestPoint) { + viewModelScope.launch { + prefs.removeCustomServer(testPoint.key()) + refreshServers() + } + } + + fun startOrStop() { + if (isRunning()) stop() else start() + } + + private fun isRunning(): Boolean = _state.value.phase in setOf(Phase.PING, Phase.DOWNLOAD, Phase.UPLOAD) + + private fun start() { + val current = _state.value + val server = current.selectedServer ?: return + //pinging the rest of the list would compete with the measurement + if (current.selectingServers) discoveryJob?.cancel() + aborted = false + val networkType = NetworkInfo.describe(getApplication()) + val startedAt = System.currentTimeMillis() + _state.update { + it.copy( + phase = Phase.PING, + currentSpeed = 0.0, + download = -1.0, upload = -1.0, ping = -1.0, jitter = -1.0, loss = -1.0, + downloadSamples = emptyList(), uploadSamples = emptyList(), + ipInfo = null, shareUrl = null, error = null + ) + } + engine.prepare(current.servers, server, telemetryEnabled, singleConnection) + engine.start(object : Speedtest.SpeedtestHandler() { + override fun onDownloadUpdate(dl: Double, progress: Double) { + _state.update { + it.copy( + phase = Phase.DOWNLOAD, + currentSpeed = dl, + download = dl, + downloadSamples = if (progress > 0) it.downloadSamples + dl else it.downloadSamples + ) + } + } + + override fun onUploadUpdate(ul: Double, progress: Double) { + _state.update { + it.copy( + phase = Phase.UPLOAD, + currentSpeed = ul, + upload = ul, + uploadSamples = if (progress > 0) it.uploadSamples + ul else it.uploadSamples + ) + } + } + + override fun onPingJitterUpdate(ping: Double, jitter: Double, progress: Double) { + _state.update { it.copy(phase = Phase.PING, ping = ping, jitter = jitter) } + } + + override fun onLossUpdate(loss: Double) { + _state.update { it.copy(loss = loss) } + } + + override fun onIPInfoUpdate(ipInfo: String?) { + _state.update { it.copy(ipInfo = ipInfo) } + } + + override fun onTestIDReceived(id: String?, shareURL: String?) { + _state.update { it.copy(shareUrl = shareURL) } + } + + override fun onEnd() { + val finished = _state.value + if (aborted || finished.download < 0) { + resetToIdle() + return + } + viewModelScope.launch { + val entryId = withContext(Dispatchers.IO) { + history.insert( + HistoryEntry( + date = System.currentTimeMillis(), + server = server.name, + ping = finished.ping, + jitter = finished.jitter, + download = finished.download, + upload = finished.upload, + loss = finished.loss, + ipInfo = finished.ipInfo, + ipVersion = server.ipVersion, + shareUrl = finished.shareUrl, + networkType = networkType, + downloadSamples = finished.downloadSamples, + uploadSamples = finished.uploadSamples, + durationMs = System.currentTimeMillis() - startedAt + ) + ) + } + resetToIdle() + lastResultId.value = entryId + } + } + + override fun onCriticalFailure(err: String?) { + _state.update { it.copy(phase = Phase.ERROR, error = err, currentSpeed = 0.0) } + } + }) + } + + private fun resetToIdle() { + _state.update { + it.copy( + phase = Phase.IDLE, + currentSpeed = 0.0, + download = -1.0, upload = -1.0, ping = -1.0, jitter = -1.0, loss = -1.0, + downloadSamples = emptyList(), uploadSamples = emptyList(), + ipInfo = null, shareUrl = null, error = null + ) + } + } + + /** Selects the server with the given name (without pinning it) and starts a test. */ + fun testAgain(serverName: String) { + if (isRunning()) return + _state.value.servers.find { it.name == serverName }?.let { server -> + _state.update { it.copy(selectedServer = server) } + } + startOrStop() + } + + private fun stop() { + aborted = true + engine.abort() + } + + override fun onCleared() { + engine.abort() + } + +} diff --git a/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/theme/Theme.kt b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/theme/Theme.kt new file mode 100644 index 0000000..a4f8d97 --- /dev/null +++ b/Speedtest-Android/app/src/main/java/org/librespeed/speedtest/ui/theme/Theme.kt @@ -0,0 +1,94 @@ +package org.librespeed.speedtest.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.graphics.Color + +val Teal = Color(0xFF2DD4BF) +val TealDeep = Color(0xFF14B8A6) +val Purple = Color(0xFFA78BFA) + +/** + * Download/upload accents resolved per theme. The bright dark-mode pair sits + * below the 3:1 large-text contrast minimum on the light surfaces (and so does + * TealDeep), so light mode gets darker shades of the same hues. + */ +data class SpeedAccents(val download: Color, val upload: Color) + +private val DarkAccents = SpeedAccents(download = Teal, upload = Purple) +private val LightAccents = SpeedAccents(download = Color(0xFF0F766E), upload = Color(0xFF7C5CD6)) + +val LocalSpeedAccents = staticCompositionLocalOf { DarkAccents } +val NightBackground = Color(0xFF0C111C) +val NightSurface = Color(0xFF151C2C) +val NightSurfaceHigh = Color(0xFF1D2537) +val DayBackground = Color(0xFFF6F8FB) +val DaySurface = Color(0xFFFFFFFF) +val DangerRed = Color(0xFFEF6461) + +private val DarkColors = darkColorScheme( + primary = Teal, + onPrimary = Color(0xFF00201C), + primaryContainer = Color(0xFF0F3B36), + onPrimaryContainer = Teal, + secondary = Purple, + onSecondary = Color(0xFF1F1147), + secondaryContainer = Color(0xFF2E2258), + onSecondaryContainer = Purple, + background = NightBackground, + onBackground = Color(0xFFE4E9F2), + surface = NightSurface, + onSurface = Color(0xFFE4E9F2), + surfaceVariant = NightSurfaceHigh, + onSurfaceVariant = Color(0xFF9AA4B8), + surfaceContainer = NightSurface, + surfaceContainerHigh = NightSurfaceHigh, + error = DangerRed, + outline = Color(0xFF3A445A) +) + +private val LightColors = lightColorScheme( + primary = TealDeep, + onPrimary = Color.White, + primaryContainer = Color(0xFFC8F5EE), + onPrimaryContainer = Color(0xFF00332E), + secondary = Color(0xFF7C5CD6), + onSecondary = Color.White, + secondaryContainer = Color(0xFFE8E0FB), + onSecondaryContainer = Color(0xFF2A1A5E), + background = DayBackground, + onBackground = Color(0xFF1A1F2B), + surface = DaySurface, + onSurface = Color(0xFF1A1F2B), + surfaceVariant = Color(0xFFEDF1F7), + onSurfaceVariant = Color(0xFF5A6478), + surfaceContainer = DaySurface, + surfaceContainerHigh = Color(0xFFF0F3F8), + error = Color(0xFFC0342F), + outline = Color(0xFFC3CAD8) +) + +enum class ThemeMode { SYSTEM, LIGHT, DARK } + +@Composable +fun LibreSpeedTheme( + mode: ThemeMode = ThemeMode.SYSTEM, + content: @Composable () -> Unit +) { + val dark = when (mode) { + ThemeMode.SYSTEM -> isSystemInDarkTheme() + ThemeMode.LIGHT -> false + ThemeMode.DARK -> true + } + CompositionLocalProvider(LocalSpeedAccents provides if (dark) DarkAccents else LightAccents) { + MaterialTheme( + colorScheme = if (dark) DarkColors else LightColors, + content = content + ) + } +} diff --git a/Speedtest-Android/app/src/main/res/drawable/ic_launcher.png b/Speedtest-Android/app/src/main/res/drawable/ic_launcher.png deleted file mode 100644 index 02542975f4c621329ae61fb70f52dc07f4579f61..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20326 zcmXt<1yEFPxW>=Y-Q9u$(%s$C-6h>fcL_)dNK2Q1bazXGfOL0vcir>9cP=wK%P{P> zC%(6y=XWBM6{S&;h>!pPK>Z{mp$Y&H@K*?c00+M5JO8!-03<$ZadBm3D@RvH7c0jv z6raS!DZV&6T3Fke1At6KX0nI6`W#-^c)N#p?kEe+NAa_EREl=);z^0mKM9R#q0!hm zs^8^7VM<2|ouQ85_iWhs0rt8j5drHb0xuu_NcKe;6 z<(c1X3-F`urMb;j8!3<@E0BD1M>h6*WTEL31mzrn{tFn_u(3ml3HAia2$4Bl%g15g zQz8U%d-T!++|g~p`>yA2pVE@L@xv!!BIdu24w*$XDfbpHd_}4Dlj@zm$6@WEWxbMw z$Ej}niH*N-UOP_7AC;QfZyKfTyNlvZr1w{lay9M4b~wQWzLN@GN&@4i9_6e&ZlROp zvnEM;|7Q!RK+1>{C^Y&{y@iz27d>Lj5^XpD$;S)&n72sS43eOGRfhw@W?u)B_`r&h z$^7(%MYjFbjAQi}5o4TQvjUa}yB0lfUATl4pIx6<=zSVtausNpez~x=%JO?@y#m7Uvr!K9# z+=#sopC|^a*jb0h#<+H!wfi@}zUICioO55#+ z@%{HPtjk)wyWVlE90)`PicT4z6M^1`qB2Ia3l#hUN7jW8^OXeyRuh6J17#hEULz_r zj}R$>I1h0TwoyhV62Z2D(1^hEpfUxHtn)QN9D?DEVZI0N8N;+IY8t8z-YqvxpTOp}z@df_uSpf#j5UAM;*(lBPM%L`H1Vee(09 z*QDSiJzHv-f;+Wz0_^t5Hua_CrRk*}Vq{2lNGyz=NxMX}L~HMlUgS@0zmk7NZPN`2 z49N~9#6!nVsd|32|H%EZaGI}}s8~(4N40hm$C~{>az-$3K4Az?Up)6(am?2DOR%9)RA0};}!R+ zyp-Ir#!ZW?m93Et9o9+us1aF`Pp4Hcc9U_)-omgFnk8GAclXb7I&r#fCd9_g=Edgf zkneD026c`<&DZtPHO-CeFy1ZGRqJT>Xmzq@pY>Yx`u1q$U)W9gb;7mnH9U$jv@LW+w|}sx zcwKJ!yYZ^kFZ1DM+a`(T({>y-^6aJn)?GoWj)*5_%%YTH*IHauF{n~pX*RA<#p z)J4=TShD}kVf#u@@SVQFN>6L)rlH7wZ9!)V@mO*G#lq1n+azGx-??~9b!_rmfhpP{ zntT{v7^ZZKX~vf5045D5O`%%*6t*R*WrIupRY+8pT+Ik;3Vualh3_2K94|M2W4*)P z3Z@71oyna)I$`V%*$i2%;EW))V7j1XTUpzzXXc%h&y&~LHQBAo?dJ!MhrjoW_Z2rM z7gP_Sj~Y*c7jt)ePad#ckPb*I6dBW$Zol3vCIXZnln1O3(j=lT>9r{fH4kkQ^}Tht zj*P#IBkczcu4}9Pbe6fQnkx7aw-n?Qk1)A!10md@|@-{=`-B)UHACgbF9g|U(o3C~VO1WZ`SWyp|3Sg%2Z+9$Z_Ih!|Gd|By{v<-{TSJTx$O}RT<-YRPQeiu|E&FVUnkl>RA z-1;rwc_`jz?h6g^EL;Z9qCYLt+V`C(`#3zwOREmZSgP->e_T^rF}O9b7bbf1ysuk4 zNMo+!uBBvPs(;kv;Md+hUQ&5NQ<}Z_SpKvGZwJTcIKR42q|fK+K4`uFN8v6##qnXe z#ouS)q?>=_Y?(BMkgR#6gWrq!W_9FA=WdVO&NJL!`&s5tWyiE&;70i9Wtq=J(Ai?z zukP&AegeE{S@mA0+3V%!w)2k<);l4G5>vk(whumz7ZZ}wqu-L?Po zyXbKo>%1A282jG2-Kl@yex3BEw5O8M$YUICRLDQ!*22HyzWmP;)fvH=_nLHD_RsOx zz!&8kl{3>hnocEj{7F2#S6JwuSI-|j@Z7*=63#?US^~fXoPlEfwme|~pa4Eeh^l)o zo@9D?V$VDdbS4NYO#M3OpssVx4^8$%X;P1 zjsPg|EDbxI!GMI%W;=!e5ndpf2w$KY;1Byn){#Ry0%%%2z=kZNtm6T507k;A^cQgw zAOVEDLg%E8z6Y5mVrYKF|uWni2lm)l%*#J36S#QAyeyH5aNrZJ_VD&hn7%~Gr7C;j?1GsK4U?T*W09E>q9KI9u zuoSwb$k69xfgiVZuo3KQ(7VLiCzO{-ji~pj_p+fW(s_h~{xPWmX7%^qEn|VadOjn7 z_=`1Twg`pmcLRWIf*93}j0Tv{U7-Mspu#D~<3#p3V1dHJ=x?sEsZbKOZg&8WXhyck zx&lrhHlxsvbBMwE^Ei|?dVHl4MH3QhAU~%Kr`nuyKrdqvxJ)KSmj!_SV^5O8m5?0j zXDK(4RU;t;Tm}o^2mVrzhl%W~ssg>X(}#X;s5fnrfzEMP0ch)7mv#st4qLW>$3Zll zPi!=x`|X7vSQgEK5BgW$3kje4J!3S>IbEA+A96<5W$}a4A1b$~iMR`1kPXTz;+FZt zc%aDs!p}gd@QTf305y32rfM@+hFHhHZ`i3>+S=PkaU@v-o?92}Zu6{ljk!|WtkVkrTClU~p5;J9-Wt%zF%5R` zQ?U2$P@bP(%5^g+Aczu_+k=zBJ+{2=vv|s4R7o1%NxLnavR;Co)J~+Y2hi zfLk-JSR6uib#*~-7#d@&5`jpVv;?g>od%Djijbg_Aj61mT3Q-X6cRFVEgO5t-gqYR z;OJ=dm-&HMyTbypx zkY8P`lARPcaldr2RZ?rID9z2y9W^+0?36V{jLKY34=~0BPz`=;UqO>p36F@T&vxy( z>FfCxtNh!~&vY@h&>#lg-U$m$7kmw_KU_5j*M`Jz?nA+TBdb=-Tm0x>>b$NH3*iICJEqidfy_tk^? z5iB<&g~()lKN$B7eot^22M34ahj#u}VoFkGK)@E9hOUjx`|58agEPda7g`7+b($#% z6v6Xh!dn&Xr+<241t^tiaejG5B3s$m46i+QTil*23HM>yHif)zpZMX`3^2f-!&NKn z5eiz^bw7t9X9@`k{mOTTL`O$^5wH45Uq3})OK3k-i#c+Xb?5{BP%K&VglbWS?_-rTrKAX|rHbx#9699g)d1c203uPv>k|zB*Vj=cp{oF| z7gLjO7`Cp$Ud_$LZ(ch)O^b`V@inWgB!KU=RPYTtgaCdWp&FT6f)bO=e>-kEVs4Ek zP~yf1FWFoH9{qTH<*^%HoCFP?6~W^*mzyZ&RR!Icp&FhW?gI_JU)>e<)-PfQ60wZV zy>xDr8L!#9u4}O6;<6ut#;6kRZb^4w8tT(is7j!LFSh# zy`;*IAv1U8(66&r9CcFpxlqu-?>FM&hGojRcqk}D-eEL#8u60E)XW)qEhKwC*2P?} zay9306Pf(BDp!n@8$eR&rPdm|A=hhQa69JQf@{t9v$3@;Kd`pOA1}(brTcdziMz8y zR60WxQ?Vqv|3l{e4kRc@quR-7EGRfW=@T@()FV7hlPN|Fulu&l;$q`0N^Yj&WU3xw zHt<6Y%>Q^PkpUR5VxAHbqos~z67)~yGU@xI}n9GhBU z*q~{V)Oz>& zlwZe}X{4ktZf-8Q8#zFJwl+Qe{=;kRf_j}MH+ffohh6Bus;U<5xsEA@Bw4DKDO&N&jcX3Ly^2Ky4vM3wvtim{Z#-^ar zZZ)If@n){g#l`uN6=f@02(5=@wV9XqosZDkioTjb0xt_Mukw2=H?JCqq{`(Hwfv7+ zb*&?2Je=#9KU4!D;L1>eM~{n{N~wIDE~{T*FZREoDxmIyses6wBJsbOzoIXJ!fI+9f1~eA-NM7EP9#y?=P-kan7#_CW5p} z#iw^%v^-5-J-g^_yh!QAxgD!NQ&N_E5AW8JXky4?SySZ=YC85xC(MLjj$Jyy%-bTM z>Ab$=ILYO>{Btr4#@H>JuX?B33*DpnYU#xNHnVZ|7n!g-18krizrBg7>ctKBsydhF zzH+^4@i96@HT%inj&szIS^N?uc6t}fx#AN2rd=W?||*MndML6=3(H9>aSSaN=@>q>D4t?K&-n!{J86}O%wS#uQ6V}&2XW|}}% zXg^!SKW#YRm+HrC=oc89dOrU@zdrTgGkKNOAmLV2SEv0lSjkreYL50m&<^$tGs+4vF)m?LF;R~W-0sI zm-ALn{l&gMWODK(SimZDG5dD*9ulZd=@!~FAHe(UQpy@jzRT{lWXWc^38exyH;N>} zLfb(Lwbzo8p_~Rh2H!g!{)Duxo|3oo!C~N&8@0Ih4OdlQwVZW6FSKEV~2+$^=pS*`($j55$L`qhNG%N8U6jNtR8z+Ns{LqWB98s^Mxs426u4|#*j|Rg(hvK0nzSmROa^EmPA{#HmZM$G=>H@ zCWrkuN1HmyH-~oo(C{Dd9Tyq|EqA8ICF*(JvTFmM$UM)*Y&%_!2jeWVQpWM{@nPqo zpET;fYs18d*eihjZtonEy@E=z(ZF-Lx>g7gH1~3!O~B7_GwQIsvMKIAHJ78r+|+F? zhkfd4g$Ao(w2|@U-ZvW7%F4=Am;kyMQwsl@w}(NyGOg>ww}jnYi>K#ibn|RJubL@- zxF<%_uGJ8MOc>=G}&sTd+nrI+k!&U&wKD_NSvFQ3K1)`{|(s@m=9- zV|P>2{Lz_lJzAW{axV{q@)WTR3aE96GEV5+ntsBEgrT|$ht{&PGXK>Vmtk958$QnM z#38e5wQ(Vz-O>6pE3uwGaP=8bZ(_{ZxV!AS9hYA3ChXP1 z-|r|XTJUIyh=lipn|+o(>7Cal6zlt}rZ?Ox&QT+oZ`Z{M_(lfxbU)1(&<3#8>FRI# zv(6$ka(Q9mG@DDhcX-q4ndh-&Ado2p~&4I z`ud29rU((%9h*F@uVYslqWUcYTmPZiz#m*P(ug{Ev(gE;;D3-223+`uL%1#gPS`Too6 zl4C^-%)bpNtgTlk`&ZMEWNR2G(IQh!-US`YES+ZO{hfeL+wl}!s2~wDT3VLp=PRYj zwSXtamco{_S`pkfua;z71WrJN)m3A<=5vM?8#sH)=l6gA*mT=+aqF+5@=~U0yLEiv zVYFfALvA*i_ww&xo1P{(@`I6TG8L@4CCS3Yea+6d0DTXG@AOa5BQ-a%e>3TSmzA9# zz`l02XdwWSD)V*bw#l7Qr4P@SSK|-1b8W@q@E#~gl9UWa4`zph6Zv6HIXyaif7_(z zmzNnj2%Ey|XBa-WzQ=f#e1B>32PVANSu@fns2dxmhSRGrSp&+lbzby`&Rr@wyJ zV3#me{KKVy+o=(Jaku<{;0n$3*UFv{^W2S*AsSSu)yuhnHB=(z@i(twF^&3cyttfy6;k= zgjR#smkZ$pjHD}PoC4Gdr2@4+$j z+fRAw6gX1(CyIR>3I7JNB9cf383J1)VtKh9J>kmen zVvcV+S?4Y+DY7rrQ8t|6a}&Cv3?trxch_o@k&#F#<~KuTHG|Ul%!(hN{y|&0wH!vw z8J*SSRxg-23shUFFe*%urnNGAnH(&jo;i-;)xU!(HN2n0NEmVjovBNuFtmcP7N4}Y zQ-f@@!^pbX&e1!+;L5=#kH>Fxt=Ih4#-q&Y!}}gELTh`fmVmy-N{RfS;REW74Tc6a z;PU0CK!Bw1r?A}(4uvPdYOBwg;MeMCuGMeRpiJK!X-UH55a-e&z4;&P=;oN(_G)?Y z8~0(y?rAgN*-KY^?o(6BZU+l^_bUW~Sh{BDQ&AtxPKpMvDRAKljMS8Oc$Jiv)+P%) zhFh;JHipfg+&X;XG~FJiA5NGs9CqNf_-hvSq}4On{TnQ zxJMQ|NKdv^-A97zj=b{ zE=h=5b~Sl`FNcgflf2Xm?`1j(1<|vw>wpwgQW9>&SzCR-xwuD?EUCxb%G5YEWFKzZ znOD$fj3gx~gYUnL2i`Z-)4?+a@8gR));WEbzO(nJBs}-k1tYq+L15vC0B7Ano%P9} zq$s?<9=`Q^QN5>zat&d9Ne!gL;q)hCwx6}vS4^jK_=RyexR#tS0U=(wg2s9UPy4Ue zc5Pxmd>_`{*kuwYCl0#6zz!pM>2n(ip0XT6x#~p~7mL>QgAQcPa_&}QFmmEjEj>Al zYyfXndbZ!;CuSgn>a}+7FR#Z)d1HO*O5xEQvjk;QmYkAYtJp7p;R`*49u}R-_GeXJ zQ}N(3nqy1ZEVHWK?+9=so0sIDnqTw&eyLbOrz>U^uYN%(XyA=&zeSiilsRs;`m`AR zn#UFDoui6zY#is*5VxVf`gFJEpPfM=<@<`>EMunX`Q5EZci8bErHi(S!gl+wXBGFiW6v z6%Wr6ULn7pT+b?_e4t_k@$dzEI&ijM99=q`y$~*9QQ@N@&PTE@?b+v0b7y8cnh)2* zxH}b*@ZU)Uy^UpLWZG#S5~UHlCUNPJ*Ymp8cB6^M+|BeHeg6bbhQkbSzh;n>xv?4Zk|Euj*ZyqHX)@7cn} zTBg(cu4y%G9}Q%z`qO!|%*N4uo^Y9n-;cRgLsGU=h-bB7?epTedhvjV+uhx6djE=v zNtjB4O{^yh)78fia9NCX&d~BO!15ewnQad>C?Tos#xMD2rZ5?{T0>9|uviks} zF?wW{h#-NVw-q&h^chq%&UOzwDAj-Cn6eX<4&auNMfDU)^N9%@GK+jY?|gF`Qm0^G zST>b{ki7$tQv`P7KfC^yqPd@Lo!xgqCFM{$ns91^vHd?W5Dc2w#sxbEb0a-vS8F}T zH(~!{$jh?LuaM5;;^hlc74cfO@pVh@iD6FpAScAdadyyvJB zQZ04+l$1SZ&mml6<2eH+Zj*LTXa zwj9SZWT0Kw&)fwI(J(Fo4C(Mc7rx9LIXoevZN;9~PDByo0BIj8Ku`Jm3Tb6~fA_FO zMyP*ffC2`r1mL-zuetz7O><>k;JQ}A^$jmXiXzNm*=escG@b7vqIEw1J0hM3{|*|K~oVSo~; zL&^r-#*bW~xqr&W~5JWr27aOaw(%Tteqk_5b+ zaGzw2dt{sH%=X@R%$EDLZkvdT=I}2~ebjntOoBcih@BeI+8Vq2F*_Ji&dJ9!08Nl% zEuOpOYeUuZu#R0jgmZJV+Me1L2H<@7Pp$edfo5E=`2T@f<)5}n>u)I6!G zaI&|T?f(}XdoU}Sz|f~Y0DB!Y|A)Q+V({Qt0pB_|xz8Hr1z2Q(qm@S3VU2GE3Zf7d zGADvvSoW>X{OLGY0FS62Hnm|Be7&Pi!)?x+S~|I{%0?p{-u20h)3wiwjg8Gj0Hmpv zQsWWvGjzdXt2vgva=pgLOP>V_#j3?^HX#pxi`80u&QdWOz*2ndXXKxXfZkm=!FB=* zyxmtnNU>!(8`+}9Bzi>0{JkjpyO@A_tqV#xh8ZI zgF*?Aq`LM*w^6+j?v1B#aB=iHJskh|-18mOlrQoJVn}Z{2KY~+$O4|f%TwFB9Pd>v z6<6N+#sTPmHc0pT++fy~;YI{^ItTzgIg*ImQki5`5ne-N^~_hM$!yZ24}^u-$k<_n zy&3V5M8rfU>|@!?8$Ov^G>X@hP+gGd>};LKa!&XH|J0TGX z-%jUmbf%zP_Og=doFy7*{zSIFz;Zw{375?;RdO%arUd4_jT@yt=5uxNeR@YKwGm+6 z|2n=FcEyXJCww31Vc5Ai$E~=vXGsn9Z}t4G;Un*Q^U=5&8}H@SB@gO2c0#-?Xv0#UZc~{oua;7D#a%@U;RvT6i zQBX^|dgkAd>9m3_Io0q&#almwj}$m4+D^P2sVUno74-3>fs4-OQBj0hrvueHDezJ%{^s>G z7A_iW(=BhXapO}gMKy_d@7iCcW1}R15x;kSKKlPGfTpy11R);jL#|&vZkBsClyZ~N z4lYAp*GDRsAMyes?{au%ET2xh{8x)0rJzrTixirGAVLh90BQQ?0=uPP12|^J=CpVg za3{#l&VT6##-LL>4N{=m)cEwq+Qm$&z=;qkLsTXz-dK_!t%!g2aFm+ssvVmoJ}%zn z$_fn$r-i%_W+2y3&zGAv{uM2sj`c(uMHL)s#k5}DnfZ+`>b_4m9q&CU6x{~Y-eq*e zWqFp)>pRMR?s^fKJPSUdLVT<+n|cYF?spr!=uF|e^m_^tOq@h#(9fcQ65cGvea z_uv$g#FwcU>xv|WxxR9-cA@3D*}kZqyf|mZ`sJmqF)&g#K9X0#0~FfEo(AuJHZ`$O z0_7MuB+Cpq5nu1?R5Uebt?G4oNzdGtPTsbCvxrA(k_B5m&_lxh$h1TAzw!@@D7CLe zyA?vL_Kv$d+2nTmifw)@*v;bN<6h7`G2%sugIWzyIH2Eu9!KSsz2?9F6r2(E2I|~= z6(_s9W|pa=7P0#HrhU$Ei8)(GkBME`xI+SL@Ofz#+puUfdw*M<46(+Tv&aMPgYGzt z=fg3jD1j7Kn`tZhvyHcj{0u1X;CQwFoa4QXQbAN=p+8bE>uh-iQ6dXP+||+>n6+@vjWarQ<@WmWv-{M}(ji~^ZMeU@JZm!} z7Uj^4)YM$N?0G6^wYRm^fll)~sDEN_KYyB>%fAWw9~00>YZOnrH|vjiy>_0JR#FP; z09G1JIai&;)aTniZ*>!YboO6Dz7h~hIz@VAJioxK#l=xDz03W9Ac72?kWhNx;B;z7 zRD`n`moM$2*b9nx=Ah6cO2!C8j*;I<(m(qOJgmm1+VjD!6V>C#{*dEoUznPj^eif+ z0nJc3n4C~Z#HY5A3Uv()XYbP3)?3{%{+jDY;-6H9uM7(0kl>8yy$a| zm&uwgN46Te9fY|Th=>kx>YI3SdYG7)Z6$~5>gqqicKo{Gah#sH2u1eO5HYWftKXkM zh#`@1r$3HlJ>MI@^F4m5G=HG_0U+tN+JLjuBiojl*uG%e2={8&klQISoh-tk0fOQs zGoJUNwl0K{N?CdDKd-ra5?CwDZ7Bdj9ElJj}=lJ;VUojxV27!ZN%r)yYx3z9ZsZe2$De~ zprTi9FZK6*g-SuvQBzB}2R9qp$ulEVS1U$=T7Iop3n^N<{Yx6bY(W_5_TJ8=12Yd# zQ%RBi)D~3EjExt5*6)gvOSlc$J&n+ahek{~>g2Zgk`lVro!uTPN}H!PKte+5vLeBP zE1kCwqj$4oCWWwBx33e`$jzvRaE{D`HQmedO46oYu!FN{z!V4y5^YNc6sWO#Y8Z-Q zI?SKY+Vz?4*wf`TI5{~L3JN~Nhy|Ze~^XLmeNfR4n0BBYqaBUH>jEEjKv-CmxZt zJVD58ge=mW14sJ7vW){Ts9E#0xB&y0my4?LgVe(yK&?+*y1>c?UTLme*3{U5u39D; z;_n%oApZG6OIVTeT~4OTl9El=$Y>FYKxJCHvu(W~Z3eUnt7m}@h6XiKox_?2^$l|} z#&0RB7@x5yezglRL!S94fVSOp*#gz+Jy?;AlhLD5RW*aYkKb}MOHcIA=4`4tJlg=P zI@AhVxxI_qDrh$nQn7B%@y3phm^q|~6tQPDq9!R@imw_$;{>mIA6%mmcMb?Y)sA(GoLUoUf5vN5|v<(1F2#>{El(01vU= zdmOL(m6~#g7(Sg@e}Z2p<5gts8?y5dh!qr%*hysKI=k1WlB}N`nw6RiD zLnP+dM&v%8%E8rIRwZ!x|{jB^B%y82yw)y8aP?pq5@h+`{_?K zw~992o7~*oU{#1SHS3=q9grFpzI`~gAuXHeU%yi&_Ghj)n0bIyG1_}^=yN}?h+xmb z1PBKN7&0q|^?W|Pf-_ZMY)J&|SRLJ9}q)eYIyx z5da7G#iBAM7SV9?uY2gbu^5};`+QMy5mk3Xdb^6@oObAVzMEUeis2uLnM#KWT)7aO z;2WmGbw8M6+^AraKo>$zVc`J7ok=31!-K2_=~yKQ-SCJPtSX1UzbcT?&~Xb+L(3Nr zJEJmHb^~`;wRXXW=Qj36wOa7E%Iu<|qHQ)znp!u{8zX{DKxk-a+vK~Ckzchbi=lGM zdD~*gE01jXW*axoAKd(+yY%zlW<(wSRK zDrtjb#!L;>G`s?Vj$8!erR=pDyV~)KJERW<)++5guVJG4>!`y8SN4tt@gBTSQTWK- z0v(fEtbsL?lR$^PgiZbKV%nG>daiQ#&-wY9&s0*0Xk=_5Na(Q$cyjM^fk#1(Jt12I z`|>hwo}jvW`NaJtOCqATi+NsM!i?n-#DJ>nW zK`MkMNs6}zSrp!#3zzvl$Mm1O#YiON;Kw##T3yR$L)ETu$}0&G5xUp9xLAMfw4qx( z%#eiDS>06Mw@tM`^Ddv34kiUj>NUE0tA8h;*5j;ebrVHQEou0!t9GbNW>Lfk{&{$C zx&WXJsuxn9*XR7^ycqAZr0mB-&jp;r0*Dy7!7O6%?;Okvj3F-2^HKQg9GL|fCGtE^ zoWVPFmhV4z0Ucglpf4zU21YQ5XIRwY$`wp1!e?N?p{(l<-CUTDOu-lYLfN}qU^N|B z>{w`RoEtUzSfucwgt-Hj_VmW(rdx~mFc_+BItMFE^!w*Bg5ob3zOgmm!HnJ&6zr)H z<34|a%b{?0?_8^A=UrS@w$7Oy854mBKfusw6id33!HuyZObrDSEBVD5>0j*8UO+xc zMkXIMQ;gQy@AC3;cYNX-9$0*)bKUHOksTf6kjZ@Nd?l+79v z2}gknwEeLVhnS|eu0|P$GqmGu*x|Av))5W%q^W!Co?7ewBqg0xr*{jfLGxmhWTW#X zrZ}`WNg&}!=X9he+W5x3D#KYdFE8J#6NhbbsvR6Ce`IFjjx|PaP)U6mqZ#}=xGu0m zz-Q-4>+}Kry9*E=Dl>3%wb$jR_jry;AOq}FkaZBM=S2{7=D6#aB?9?SSvgsC3Eg zF?ad1F#wP6$Ch(=jkNR2F^CFoXLk5J&$9|s0$L?`c%(~J&aj}O5nVtVsTLP{?PC2O z3v#vmI=keEjvFD-+qz8hk=C1`H$yFT)c6Kp)Ww@n8ONNQ*V`3kT<+I+QPCY0)E7d{ zQVnH2z4U=1)CdVNNeQXlFPU)9_dRzRd$%UlJXV+XYJ;?0qp5#nr}(RGW6wVF@9hUz zS!p-OQ*Z6CgIeo@W@!>7)W1WHb?#M{{B(!r&@1QlQzc=ATbwQ$z))h%XqdC2aZK zT?ge3jZ1Pui!}wQO{q_RfcyBGBz}mZXuIz}Ud^fut{d=_IvoD=!gS2tgUUB$1W*_B zA8(sh=yie&f{R~YSy@x{h2OdhqqP`i_P_AZ39WW8`pvFP{pnbGv;W%4u!fQs>%$kHLfd{v}pl2rK#s$;lo{_U}9BD6Qx*7l%=uIO%|c?F-&MV&5R z_^#K_8{ML6lQGeJ-$C2{uKJQa2t$VX>n_Q2>uWzTJ#FM>y-}$7!nZZ0jD01ToOUmg z9twVXx$K{by|#m#rn6MRS_N)-G%vI2wY_U5f!hG?&kEd4X z@bKTi`I%!Irxw_a0mCUb00n2p!Y_*pg%mLLB*xP97+`NYBO@ zVb_mS*>%HK42K&to3HS%!-z?`WX`qsA7X`wdRj4yYAL}JBEp}rh$ zpS}FGs15R9px{s!^z99IovcLECt$PF_O{X{IQvCfI%6Z?f2z&3=DmbPaThwC$UK`PgvY&VbE&<9$lUwgY1=}((;t$14nv) zoBrJ2-%sGtHphRO=I-$LH`Sh66jXsU7<}wL$?Cmj{Y+H9e~v0$WY9UOTC%UTl%F#= zA#(StE+WC1*|oLZnWT}B3eFw5bB&PVExjx5;&v9wm|I9;FigA%4B|wN=}9<{8Dv$mn9`v|GBsc@7#e^Z)qM zbzxcyfpK3a7(>7finx85x6?!RAJ{z&Jn9>~~1Iz*=3+MEIyzKKp0f<3#rM*V7#>B*&WQ ztm6f5tK@c9;M`bNMh4;I&5AT4653eXSrEMbZqEH{GgmmmPmPfrUfv}Sa8f?kv+6By4;XjNPI&z|zI1gMYcxZnkT;y?pVduvw27+>VPpy&4cvpvmj99C2>VljsFM(iZ%xk09JF0ptDOn{^ah63)|Q71so)!Z-B zT<6I}Nx0yPr*gkhB`yFoX)9yg&)^%Gwbm#whl)M_PZ4Jx4`tWJ@!J?n;g!fP6D2$u z_1KppPb6DeLW9RrmJ-rfvJYinOO~>ZHQU&Vu|OEL!U>HWO#=l%cO z=W}N6`&{Q-zw7tCCRq#H$bQPX>h4cI#tLHPuYW`h=vSt8)=mN+Y_xR%d@E zxQSi>5_eG(3a;ojI+kO=qRttwlRS8)+t$P+^9byR=l-!-{_#-NrPyMNOSi!nkF21H zr|23FtE=rtX%C&oH$teaav?Z4UgA3b2C@ zcodxC=h5Ca_xh7_bU=d=(3Bspf2_C9{bP|XBg?=2dzhg_GG1v^|DAD}2Xwipe*8|5 zO;#TETf!;iBH}h!ii($Qik=5q+0V&+OWweUWP{lxT z_O*&tM+r3w6%Ii=d`P$po!*~!u;<&5|1SYmdFAu+^2dAJt+yC-qsY7JJlbzWZJI4L z+&bb4a4yGyNy$0{MtH^m>{0@oziaUbKG;Uj-N-2I!S3N~Bh_ID7t$k<+!;qW^ye)x zL*W;)d`Zdf_-g%x$#102TLF8k^~`(b2fHW+yL-GnR}anffLYPU;=SluuIar=H*z~z z$;FcPt2YYF1Kf!}MX)&Kf65ddm6p|J2hd7hQ+Rf$axe%e0^FcPJU03G&!wikpayHC z|7=CQDX_`PCg(|Vdv>k~ZS^#I7jK}G@rri;L~ z*uzY7u#O^q6?(KQ}UB7h59DSpIo~#Uf zaTh`k$3FZC?9SK6@w4Du=-*FNACtH5FTmrDkYK^hUY)1ISyFdrfF29!+b)~^UPkPK zM)^}m1#BJvUZU%LpB37rnIS3DZWEqCUF)~ox~2QTs8+Q0%ge&WSGjfYkpeRFxT-Nx zMFX+~xXT(SS}wb085EjW4ZDq*<=v6YYnnYUkVu|wUH8yCo?p!2woKg>bElNfW&pQB zvcmDpn=G_^q)FTRv@2QUWL}z{iV`32~>Ob%;o@LbZzI%6JHkR-6&v2IzA@$pUHz7jhYh_ut z5vQhX%gnPxlqDOiYFmKLdbspOts8_+^5w{OuJ0EYe>r&W$16=*tKMHI55-X$hR?nc z5OB7Awl@07OV)PLBXa(KXvh)o+k*`{x_;b;tm(D=jn!~KnMRatXz~euT=woAKPzT= zzQ~CY#wZ7F9Y|pfPZKQ*on5lS@vv>q!PKE)C*o3W-iO9F&^3uVsKXjf3U~Y?haI?n z2Dv9~jg9->9}L`n8VpqZuTHhvKTGRdZkRkJ;XNJYoVsH;S=m=!Ix40*W(?u{YUy96 z+piSVGeS-P0-AULO`fu{76WqqQGEUIke{F5F13>?*-I^J{k2jX>ulNszgJCCS~Dt5!(u@v9iD&4$$pvV#lSGzyUO#rOPa~d$|e|_+0{i+<;s|`KnmRx4$=0y@M zc<&%Mq8I`kFp;G+EIHYJ*&KpT` zLZiBziYJ_$ABJx5 zMJelw1N3s2C~SiXqZVa|GXfr?iCEcIleMzGB-0lYNx)V$&X*l9)Y|K^BR=GkcGW+B zx?3Ym>^$q&&{s1KlMQ=4w?;moomGi7=j$hf7HFg!oCXntF$)1!W1E%S!gOZEdW>Q=VWUwH)oeO9WE;`v`xut(Azz&_lVO@d<9eSlcd znArG?Plk)dSmsl!P!%1Vif-?Zynfsf20Y^aZypiCv_?GJ<7Sw;lCA15PXk3@khpQE zaCT)~OzV7rayT=rdIT=YT`Zi!x`@AmC@aUaoFO6%=V1uPa%&J2@E}=3J54Ix{83@{ zsu_JY-LNQ3gnX@r>x-|{E&u#;+a9o9F_;SUwf9>%yMSVsvd2+a2Z%DE1i|qVN!i{Zqf(6|)~ za`cJh8b7p|vHiJw-BdyIrTBG7O0NP%3Jmv7R#YD z`RD#WKdSFL0>-oYN05p@LgUyN9SCK$r;69Ftbu39WNt_R631vdRAygCrpW zep!ZB-y4Mg*>HNGs+yeXOCYQn1EcGC>W+Kt35=14yczm5hL`IZM_V$%Cp%mVYX_o= zG>Fqehjh9OFvs|4glKdOTl^J$Lrf2u#>NC=0MG`3N81>(t0jxD8`icJKAk6#484Ma zu7V2G3*bo4D=pQloXHbwjoEstkwMalTk&hgDG6pj+I4(-hGB!{2?Hi(BvEt2QV`nl zSY73W+<2dqxxQ0!{r-pn6HSPKhke<4MR8Fc8PcfZOR-@zx%^sl!;BrGG>@_1q#+r7 zW@5C+33%dz{dr<==6xvbGviNKy4K1q#54AT9i4WNKSsGabmT*CqYS~Y+!JkDNYT0T zkbgcF-sa$70sACwS*|1)(-4@neFX{N|3&#n-Z0F02V2-Dx6wkd(plPc!h(|qEEhA9 zuK7g&Br1@{M(p?V|7tU{R@IBsMBq7jAyccs_pWg8Qu`UyZ>$(1@Mkzb{Bnx?@!c2) zCKV9;@Rs><=t!34kN*JT>)s1|YC)-J0O4}Qqbis#r;p@l{hzs3Dk0QUIbR=;jr0&0=9*sm^!%-ry8lG z5Kh}g-)M-g4gUx~b=?65*Bb8LXXpZb6^tz8CAqqk5&1U@GWj z&{Y2OZSSDPNR4U|%M@?YY{v<>h229xYNfAtyN!>uAwWM_+tQ$~o}+NBMX9zz_SPMo zOEYo#eZBR@D~A3w}j#ttR>D{!~h0BQ3UZ)$W^1 z1(Llj0Fe^T`l75FG>5<)>|fP^j>O=;FiQ^2o7oDX8yA_aOQ-j=eS=G?n$~M@*lSk# z<{mIRrpr8-IQ0N6(IT$2gz1cl6m$^i0e! zLUM;O;mv%LGW868kj(0ok0P?Y0_#s>T3JKc+vFimMtsEY9vCzHm_3FS_e%4SoHH0A z0m0k$81iL|5JIEz&guD z78vnlkF7|Z^pDKIi)pB%j_!L3<8r&1FYIPJFz)NJJP~ZGgp5EhiA3pi@*kNJ;DCU! zb`(Mm2uJ~1PZgE5My>HcNy)+bQy9=N1jB5{+&jKyny7!hSr7Ve%MjYJdR`_oAz9}& QXn6wN(l)w*)3OWuH$8?M + + + + + + + + + + + + + + + + + diff --git a/Speedtest-Android/app/src/main/res/drawable/ic_logo.xml b/Speedtest-Android/app/src/main/res/drawable/ic_logo.xml new file mode 100644 index 0000000..fed6d7d --- /dev/null +++ b/Speedtest-Android/app/src/main/res/drawable/ic_logo.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + diff --git a/Speedtest-Android/app/src/main/res/drawable/logo.png b/Speedtest-Android/app/src/main/res/drawable/logo.png deleted file mode 100644 index eccac8fb2c1d8c07f6fabe2c7ca9cac181fe5fb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37296 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%0ABbam;3Y^R7zJ$cI3*4B9~Y25|6xp!$R)kR$> z(K0l=o`+Fh>N8^Cx=gtZ_Q#4Jc8ZwcVIid`JFS%qMJ|aCL%*yJnvg!qAGhfOL^#FF zM=gFRWlgW5e;&^d4~LqN=EZO1R^;Lvv$CXQ^WR@6$Hv88nRr8{TLlZjV+9D9EM{tUR{jq5#M>~z|(3#3~V#4jM|4Ty9qt11nZ(v{Y0 zYmdW0iN6VG&cZ6Is_ecWi( zvWtg9pl(36Q+j1(WnuEDX}75k2J@)1lx_(~$pwCGe$e-XII^d4u6Cc7@BG3m&%dkt zSC>v`5D=Pwiy5WnTzE4>kV&u$+kf}qfWO=}FJkSjArq%}k{J@Qc#6O~f%^(64hNJpO$V&wI zf9x-l1eR7XWkuB%R+m0^yZtpZdhF^|eW!m@XnsP2z4cYi$PmKF9SnV`^-mqCz)Q-N+@t!1uydM7=YtyN;$9 zP%VwY6EP(C=3KkyTce-d-$M|%2=EVzW<$+06r}+VU&sXrI_;)LZcVp~;f9=Ogatb5 z367HnI4{)fp14YORfeLoJ;+b74`{Uf^S$}Z&q*1RII)=Ja{&fO!hbUs)h&lXLC&&` zA_=$EWeRW77dTG^APawRoqu`NK*KF7H%KWJ)cmXR2A3@BJ={^urQ4s#Gu zBTRi88dm5M+BaG9N59FJb9n%n?_&u0hL)9ir;*F8S7z8p^71r`dJCe?W`|Ela}`zJmU`x7hG`Y1X^6 zs`P`tUo(zRTyjXVr`wPt7FpAkF;<- z{im1|7|2FyzqU!Au>#ZO^Qsj$6r8sQrc5+Sy=cqIB->m4y7WNR#r;3TksnP^?`#^T3%kRYo=3z)zojgidI&h z1`IqatE*x1^*1lk1h=PSWSh~5&Fokfh^v|E2}CUz3@B9l^+`n;2Aunc;fy=p zMAd3ZZ%OF|Cfovb+3U+tgRQbbU2CiT%F3&}oSdQ_Un612(6F;>CZCuMejEPgjiu~^ z_an5lIu(msAI%Rkn^j)x5 z?%Y!#NW;&h5Ox#2gJeGQdXRo~hTEK&b~DocaPAleV&epO*aaiP2KsNZHOIg>U#*~y zGDj2_!6u@jIdKtdBG6f9?cK@whk>$(rwk97^cyhT3?$8sZI6tIf8+~^Ch#u2h_g(f zbp+l=swfkMC4l6QOp`e`+l-8Ix6uvG3Zlkabq<26V#Y-B(vX69mre?jWng5k< z9LK-w9zm^~&IfH{#|voRu}XfkIsBAuhXV@8K4rri_MOyz_v? zUm>iWJTbh(1G)$cK~nCEsu;AO%^XXD>7e zXS#x1S0LB0iGApz?Bu95TIhn#lj)ZrGx(xd%{8D6 z6{n)KS;mNc%=H-7AiudHgyH)pvP;4IC=?l!BzsTNT#B+25`;~_?qzbbgXrdNBsSjS zH1UU+K{~&qFl_AVUDKl|oRcPt=4I<~r&0Ehv g@5K!yV&MjyF4&w|^g|;9sAfXemUf48E!-pj4`Q85RsaA1 diff --git a/Speedtest-Android/app/src/main/res/drawable/logo_inapp.png b/Speedtest-Android/app/src/main/res/drawable/logo_inapp.png deleted file mode 100644 index 14ea78c635c88c1635d27c9f66cf9e72aec9c8ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37343 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 diff --git a/Speedtest-Android/app/src/main/res/drawable/testbackground.png b/Speedtest-Android/app/src/main/res/drawable/testbackground.png deleted file mode 100644 index f19c990e6eea15b86e3c690fdc3d5f4fb8b7e0e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 278762 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%0Am7^*4gV@#ClDh}cARui^0)E9GgdR*1oZxJnf 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 diff --git a/Speedtest-Android/app/src/main/res/layout/activity_main.xml b/Speedtest-Android/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index ad35b91..0000000 --- a/Speedtest-Android/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,536 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - -