summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Weipert <git@mail.dweipert.de>2024-01-26 14:51:36 +0100
committerDaniel Weipert <git@mail.dweipert.de>2024-01-26 14:52:57 +0100
commitd3bf2d09f740221771806789b00bf915c9f5f2e3 (patch)
tree95f99eabd763dff1907f107393504ee75aa747d7
parent466d03a38cb01e9ff9a2d11be113a81c2bdce34a (diff)
initial commitHEADmain
-rw-r--r--mobile-gradle/.gitattributes9
-rw-r--r--mobile-gradle/.gitignore5
-rw-r--r--mobile-gradle/Justfile0
-rw-r--r--mobile-gradle/build.gradle.kts6
-rw-r--r--mobile-gradle/gradle/libs.versions.toml2
-rw-r--r--mobile-gradle/gradle/wrapper/gradle-wrapper.jarbin0 -> 43462 bytes
-rw-r--r--mobile-gradle/gradle/wrapper/gradle-wrapper.properties7
-rwxr-xr-xmobile-gradle/gradlew249
-rw-r--r--mobile-gradle/gradlew.bat92
-rw-r--r--mobile-gradle/nix/android-composition.nix14
-rwxr-xr-xmobile-gradle/nix/androidsdk-fixup.py (renamed from mobile/nix/androidsdk-fixup.py)0
-rw-r--r--mobile-gradle/nix/androidsdk.nix (renamed from mobile/nix/androidsdk.nix)0
-rw-r--r--mobile-gradle/settings.gradle.kts8
-rw-r--r--mobile-kt/.gitignore2
-rw-r--r--mobile-kt/Makefile17
-rw-r--r--mobile-kt/WORKSPACE25
-rw-r--r--mobile-kt/app/AndroidManifest.xml54
-rw-r--r--mobile-kt/app/BUILD18
-rw-r--r--mobile-kt/app/res/drawable/logo.pngbin0 -> 8963 bytes
-rw-r--r--mobile-kt/app/res/layout/main.xml43
-rw-r--r--mobile-kt/app/res/menu/settings.xml11
-rw-r--r--mobile-kt/app/res/values-de/strings.xml66
-rw-r--r--mobile-kt/app/res/values-ja/strings.xml66
-rw-r--r--mobile-kt/app/res/values/dimens.xml4
-rw-r--r--mobile-kt/app/res/values/strings.xml66
-rw-r--r--mobile-kt/app/res/values/styles.xml11
-rw-r--r--mobile-kt/app/res/xml/settings.xml45
-rw-r--r--mobile-kt/app/src/DNSProxyConnection.java43
-rw-r--r--mobile-kt/app/src/DNSProxyRunner.java43
-rw-r--r--mobile-kt/app/src/DNSProxyService.java171
-rw-r--r--mobile-kt/app/src/MainActivity.kt35
-rw-r--r--mobile-kt/app/src/SettingsActivity.java132
-rw-r--r--mobile-kt/app/src/WifiListenerReceiver.java50
-rw-r--r--mobile-kt/app/src/WifiListenerService.java236
-rw-r--r--mobile-kt/nix/android-composition.nix14
-rwxr-xr-xmobile-kt/nix/androidsdk-fixup.py24
-rw-r--r--mobile-kt/nix/androidsdk.nix29
-rw-r--r--mobile-ns/.editorconfig (renamed from mobile/.editorconfig)0
-rw-r--r--mobile-ns/.gitignore (renamed from mobile/.gitignore)0
-rw-r--r--mobile-ns/.vscode/extensions.json (renamed from mobile/.vscode/extensions.json)0
-rw-r--r--mobile-ns/App_Resources/Android/app.gradle (renamed from mobile/App_Resources/Android/app.gradle)0
-rw-r--r--mobile-ns/App_Resources/Android/before-plugins.gradle (renamed from mobile/App_Resources/Android/before-plugins.gradle)0
-rw-r--r--mobile-ns/App_Resources/Android/src/main/AndroidManifest.xml (renamed from mobile/App_Resources/Android/src/main/AndroidManifest.xml)3
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-hdpi/background.png (renamed from mobile/App_Resources/Android/src/main/res/drawable-hdpi/background.png)bin3661 -> 3661 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-hdpi/logo.png (renamed from mobile/App_Resources/Android/src/main/res/drawable-hdpi/logo.png)bin5165 -> 5165 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-ldpi/background.png (renamed from mobile/App_Resources/Android/src/main/res/drawable-ldpi/background.png)bin1609 -> 1609 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-ldpi/logo.png (renamed from mobile/App_Resources/Android/src/main/res/drawable-ldpi/logo.png)bin2511 -> 2511 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-mdpi/background.png (renamed from mobile/App_Resources/Android/src/main/res/drawable-mdpi/background.png)bin2218 -> 2218 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-mdpi/logo.png (renamed from mobile/App_Resources/Android/src/main/res/drawable-mdpi/logo.png)bin3432 -> 3432 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-nodpi/splash_screen.xml (renamed from mobile/App_Resources/Android/src/main/res/drawable-nodpi/splash_screen.xml)0
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-xhdpi/background.png (renamed from mobile/App_Resources/Android/src/main/res/drawable-xhdpi/background.png)bin5473 -> 5473 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-xhdpi/logo.png (renamed from mobile/App_Resources/Android/src/main/res/drawable-xhdpi/logo.png)bin6904 -> 6904 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-xxhdpi/background.png (renamed from mobile/App_Resources/Android/src/main/res/drawable-xxhdpi/background.png)bin9949 -> 9949 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-xxhdpi/logo.png (renamed from mobile/App_Resources/Android/src/main/res/drawable-xxhdpi/logo.png)bin10319 -> 10319 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-xxxhdpi/background.png (renamed from mobile/App_Resources/Android/src/main/res/drawable-xxxhdpi/background.png)bin15701 -> 15701 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable-xxxhdpi/logo.png (renamed from mobile/App_Resources/Android/src/main/res/drawable-xxxhdpi/logo.png)bin13941 -> 13941 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/drawable/ic_launcher_foreground.xml (renamed from mobile/App_Resources/Android/src/main/res/drawable/ic_launcher_foreground.xml)0
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml (renamed from mobile/App_Resources/Android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml)0
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/mipmap-hdpi/ic_launcher.png (renamed from mobile/App_Resources/Android/src/main/res/mipmap-hdpi/ic_launcher.png)bin3092 -> 3092 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/mipmap-mdpi/ic_launcher.png (renamed from mobile/App_Resources/Android/src/main/res/mipmap-mdpi/ic_launcher.png)bin1956 -> 1956 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/mipmap-xhdpi/ic_launcher.png (renamed from mobile/App_Resources/Android/src/main/res/mipmap-xhdpi/ic_launcher.png)bin4484 -> 4484 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/mipmap-xxhdpi/ic_launcher.png (renamed from mobile/App_Resources/Android/src/main/res/mipmap-xxhdpi/ic_launcher.png)bin7184 -> 7184 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/mipmap-xxxhdpi/ic_launcher.png (renamed from mobile/App_Resources/Android/src/main/res/mipmap-xxxhdpi/ic_launcher.png)bin10378 -> 10378 bytes
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/values-v21/colors.xml (renamed from mobile/App_Resources/Android/src/main/res/values-v21/colors.xml)0
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/values-v21/styles.xml (renamed from mobile/App_Resources/Android/src/main/res/values-v21/styles.xml)0
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/values-v29/styles.xml (renamed from mobile/App_Resources/Android/src/main/res/values-v29/styles.xml)0
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/values/colors.xml (renamed from mobile/App_Resources/Android/src/main/res/values/colors.xml)0
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/values/ic_launcher_background.xml (renamed from mobile/App_Resources/Android/src/main/res/values/ic_launcher_background.xml)0
-rw-r--r--mobile-ns/App_Resources/Android/src/main/res/values/styles.xml (renamed from mobile/App_Resources/Android/src/main/res/values/styles.xml)0
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json)0
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-1024.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-1024.png)bin17868 -> 17868 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20.png)bin745 -> 745 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png)bin995 -> 995 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png)bin1258 -> 1258 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png)bin851 -> 851 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png)bin1232 -> 1232 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png)bin1668 -> 1668 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png)bin995 -> 995 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png)bin1504 -> 1504 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png)bin2121 -> 2121 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png)bin2121 -> 2121 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png)bin3018 -> 3018 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png)bin1482 -> 1482 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png)bin2633 -> 2633 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png)bin2831 -> 2831 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/Contents.json (renamed from mobile/App_Resources/iOS/Assets.xcassets/Contents.json)0
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json (renamed from mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json)0
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png)bin4920 -> 4920 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png)bin14165 -> 14165 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@3x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@3x.png)bin27892 -> 27892 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json (renamed from mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json)0
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png)bin6808 -> 6808 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png)bin13502 -> 13502 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@3x.png (renamed from mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@3x.png)bin20794 -> 20794 bytes
-rw-r--r--mobile-ns/App_Resources/iOS/Info.plist (renamed from mobile/App_Resources/iOS/Info.plist)0
-rw-r--r--mobile-ns/App_Resources/iOS/LaunchScreen.storyboard (renamed from mobile/App_Resources/iOS/LaunchScreen.storyboard)0
-rw-r--r--mobile-ns/App_Resources/iOS/build.xcconfig (renamed from mobile/App_Resources/iOS/build.xcconfig)0
-rw-r--r--mobile-ns/Justfile (renamed from mobile/Justfile)0
-rw-r--r--mobile-ns/app/app-root.xml (renamed from mobile/app/app-root.xml)0
-rw-r--r--mobile-ns/app/app.css (renamed from mobile/app/app.css)0
-rw-r--r--mobile-ns/app/app.ts (renamed from mobile/app/app.ts)0
-rw-r--r--mobile-ns/app/gallery-page.ts (renamed from mobile/app/gallery-page.ts)0
-rw-r--r--mobile-ns/app/gallery-page.xml (renamed from mobile/app/gallery-page.xml)0
-rw-r--r--mobile-ns/app/gallery-view-model.ts (renamed from mobile/app/gallery-view-model.ts)36
-rw-r--r--mobile-ns/app/main-page.ts (renamed from mobile/app/main-page.ts)0
-rw-r--r--mobile-ns/app/main-page.xml (renamed from mobile/app/main-page.xml)0
-rw-r--r--mobile-ns/app/main-view-model.ts50
-rwxr-xr-xmobile-ns/bin/ns (renamed from mobile/bin/ns)0
-rw-r--r--mobile-ns/nativescript.config.ts (renamed from mobile/nativescript.config.ts)0
-rw-r--r--mobile-ns/nix/android-composition.nix (renamed from mobile/nix/android-composition.nix)0
-rwxr-xr-xmobile-ns/nix/androidsdk-fixup.py24
-rw-r--r--mobile-ns/nix/androidsdk.nix29
-rw-r--r--mobile-ns/package-lock.json (renamed from mobile/package-lock.json)0
-rw-r--r--mobile-ns/package.json (renamed from mobile/package.json)0
-rw-r--r--mobile-ns/references.d.ts (renamed from mobile/references.d.ts)0
-rw-r--r--mobile-ns/tsconfig.json (renamed from mobile/tsconfig.json)0
-rw-r--r--mobile-ns/webpack.config.js (renamed from mobile/webpack.config.js)0
-rw-r--r--mobile/.gitkeep0
-rw-r--r--mobile/app/main-view-model.ts29
119 files changed, 1728 insertions, 40 deletions
diff --git a/mobile-gradle/.gitattributes b/mobile-gradle/.gitattributes
new file mode 100644
index 0000000..097f9f9
--- /dev/null
+++ b/mobile-gradle/.gitattributes
@@ -0,0 +1,9 @@
+#
+# https://help.github.com/articles/dealing-with-line-endings/
+#
+# Linux start script should use lf
+/gradlew text eol=lf
+
+# These are Windows script files and should use crlf
+*.bat text eol=crlf
+
diff --git a/mobile-gradle/.gitignore b/mobile-gradle/.gitignore
new file mode 100644
index 0000000..1b6985c
--- /dev/null
+++ b/mobile-gradle/.gitignore
@@ -0,0 +1,5 @@
+# Ignore Gradle project-specific cache directory
+.gradle
+
+# Ignore Gradle build output directory
+build
diff --git a/mobile-gradle/Justfile b/mobile-gradle/Justfile
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mobile-gradle/Justfile
diff --git a/mobile-gradle/build.gradle.kts b/mobile-gradle/build.gradle.kts
new file mode 100644
index 0000000..7529919
--- /dev/null
+++ b/mobile-gradle/build.gradle.kts
@@ -0,0 +1,6 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ *
+ * This is a general purpose Gradle build.
+ * To learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.5/samples
+ */
diff --git a/mobile-gradle/gradle/libs.versions.toml b/mobile-gradle/gradle/libs.versions.toml
new file mode 100644
index 0000000..4ac3234
--- /dev/null
+++ b/mobile-gradle/gradle/libs.versions.toml
@@ -0,0 +1,2 @@
+# This file was generated by the Gradle 'init' task.
+# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
diff --git a/mobile-gradle/gradle/wrapper/gradle-wrapper.jar b/mobile-gradle/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..d64cd49
--- /dev/null
+++ b/mobile-gradle/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/mobile-gradle/gradle/wrapper/gradle-wrapper.properties b/mobile-gradle/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..1af9e09
--- /dev/null
+++ b/mobile-gradle/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/mobile-gradle/gradlew b/mobile-gradle/gradlew
new file mode 100755
index 0000000..1aa94a4
--- /dev/null
+++ b/mobile-gradle/gradlew
@@ -0,0 +1,249 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/mobile-gradle/gradlew.bat b/mobile-gradle/gradlew.bat
new file mode 100644
index 0000000..93e3f59
--- /dev/null
+++ b/mobile-gradle/gradlew.bat
@@ -0,0 +1,92 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/mobile-gradle/nix/android-composition.nix b/mobile-gradle/nix/android-composition.nix
new file mode 100644
index 0000000..2db557a
--- /dev/null
+++ b/mobile-gradle/nix/android-composition.nix
@@ -0,0 +1,14 @@
+with (import <nixpkgs> {
+ config.allowUnfree = true;
+ config.android_sdk.accept_license = true;
+});
+
+androidenv.composeAndroidPackages {
+ platformVersions = ["28" "30" "31"];
+ buildToolsVersions = ["30.0.3" "33.0.2"];
+
+ # includeEmulator = true;
+ # includeSystemImages = true;
+ # systemImageTypes = ["google_apis_playstore"];
+ # abiVersions = ["x86_64"];
+}
diff --git a/mobile/nix/androidsdk-fixup.py b/mobile-gradle/nix/androidsdk-fixup.py
index ab419e6..ab419e6 100755
--- a/mobile/nix/androidsdk-fixup.py
+++ b/mobile-gradle/nix/androidsdk-fixup.py
diff --git a/mobile/nix/androidsdk.nix b/mobile-gradle/nix/androidsdk.nix
index cf1ea04..cf1ea04 100644
--- a/mobile/nix/androidsdk.nix
+++ b/mobile-gradle/nix/androidsdk.nix
diff --git a/mobile-gradle/settings.gradle.kts b/mobile-gradle/settings.gradle.kts
new file mode 100644
index 0000000..9703689
--- /dev/null
+++ b/mobile-gradle/settings.gradle.kts
@@ -0,0 +1,8 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ *
+ * The settings file is used to specify which projects to include in your build.
+ * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.5/userguide/building_swift_projects.html in the Gradle documentation.
+ */
+
+rootProject.name = "mobile"
diff --git a/mobile-kt/.gitignore b/mobile-kt/.gitignore
new file mode 100644
index 0000000..306c83d
--- /dev/null
+++ b/mobile-kt/.gitignore
@@ -0,0 +1,2 @@
+/bazel-*
+/result
diff --git a/mobile-kt/Makefile b/mobile-kt/Makefile
new file mode 100644
index 0000000..a314992
--- /dev/null
+++ b/mobile-kt/Makefile
@@ -0,0 +1,17 @@
+build: app/java/src/*.java
+ bazel build //app:image-sync
+
+dev:
+ #bazel mobile-install //app/java:dnsproxy --start_app #--debug_app --java_debug
+ $(MAKE) build && $(MAKE) install && adb shell am start -n org.pihole.dnsproxy/org.pihole.dnsproxy.MainActivity
+
+install:
+ #bazel mobile-install //app/java:dnsproxy
+ adb install bazel-bin/app/java/dnsproxy.apk
+
+emulate:
+ # avdmanager create --name dnsproxy -k "system-images;android-28;google_apis_playstore;x86_64"
+ emulator @dnsproxy -no-boot-anim
+
+adb_logcat:
+ adb logcat --pid=$(adb shell pidof -s org.pihole.dnsproxy)
diff --git a/mobile-kt/WORKSPACE b/mobile-kt/WORKSPACE
new file mode 100644
index 0000000..158184a
--- /dev/null
+++ b/mobile-kt/WORKSPACE
@@ -0,0 +1,25 @@
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+
+# Android
+
+android_sdk_repository(
+ name = "androidsdk",
+)
+
+
+# Kotlin
+
+rules_kotlin_version = "1.9.0"
+rules_kotlin_sha = "5766f1e599acf551aa56f49dab9ab9108269b03c557496c54acaf41f98e2b8d6"
+http_archive(
+ name = "rules_kotlin",
+ urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/v%s/rules_kotlin-v%s.tar.gz" % (rules_kotlin_version, rules_kotlin_version)],
+ sha256 = rules_kotlin_sha,
+)
+
+load("@rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories")
+kotlin_repositories()
+
+load("@rules_kotlin//kotlin:core.bzl", "kt_register_toolchains")
+kt_register_toolchain()
diff --git a/mobile-kt/app/AndroidManifest.xml b/mobile-kt/app/AndroidManifest.xml
new file mode 100644
index 0000000..0c417b7
--- /dev/null
+++ b/mobile-kt/app/AndroidManifest.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="org.image-sync"
+ android:versionCode="1"
+ android:versionName="1.0.0"
+>
+ <uses-sdk
+ android:minSdkVersion="28"
+ android:targetSdkVersion="30"
+ />
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_SMS" />
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
+
+ <application
+ android:icon="@drawable/logo"
+ android:usesCleartextTraffic="true"
+ >
+ <!-- <service
+ android:name=".WifiListenerService"
+ android:foregroundServiceType="location"
+ ></service> -->
+
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_label"
+ android:screenOrientation="portrait"
+ >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <!-- <activity
+ android:name=".SettingsActivity"
+ android:label="@string/menu_settings"
+ android:parentActivityName=".MainActivity">
+
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".MainActivity"
+ />
+ </activity> -->
+ </application>
+</manifest>
diff --git a/mobile-kt/app/BUILD b/mobile-kt/app/BUILD
new file mode 100644
index 0000000..c3e38c2
--- /dev/null
+++ b/mobile-kt/app/BUILD
@@ -0,0 +1,18 @@
+android_library(
+ name = "main",
+ manifest = "AndroidManifest.xml",
+ resource_files = glob(["res/**"]),
+)
+
+load("@rules_kotlin//kotlin:android.bzl", "kt_android_library")
+kt_android_library(
+ name = "main_kt",
+ srcs = glob(["src/*.kt"]),
+ deps = [":main"],
+)
+
+android_binary(
+ name = "image-sync",
+ manifest = "AndroidManifest.xml",
+ deps = [":main", ":main_kt"],
+)
diff --git a/mobile-kt/app/res/drawable/logo.png b/mobile-kt/app/res/drawable/logo.png
new file mode 100644
index 0000000..154b579
--- /dev/null
+++ b/mobile-kt/app/res/drawable/logo.png
Binary files differ
diff --git a/mobile-kt/app/res/layout/main.xml b/mobile-kt/app/res/layout/main.xml
new file mode 100644
index 0000000..d3bbcf5
--- /dev/null
+++ b/mobile-kt/app/res/layout/main.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:orientation="vertical"
+ tools:context=".MainActivity"
+>
+
+ <TextureView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/surface_view"
+ />
+
+ <Button
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/button_start"
+ android:layout_gravity="center"
+ android:onClick="onClickButtonStart"
+ android:text="@string/button_start"
+ android:background="#22B225"
+ android:textColor="@android:color/white"
+ android:textSize="96sp"
+ />
+ <Button
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/button_stop"
+ android:layout_gravity="center"
+ android:onClick="onClickButtonStop"
+ android:text="@string/button_stop"
+ android:background="#96060C"
+ android:textColor="@android:color/white"
+ android:textSize="96sp"
+ />
+</FrameLayout>
diff --git a/mobile-kt/app/res/menu/settings.xml b/mobile-kt/app/res/menu/settings.xml
new file mode 100644
index 0000000..3e3bcbb
--- /dev/null
+++ b/mobile-kt/app/res/menu/settings.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu
+ xmlns:android="http://schemas.android.com/apk/res/android"
+>
+ <item
+ android:id="@+id/menu_settings"
+ android:icon="@android:drawable/ic_menu_preferences"
+ android:title="@string/menu_settings"
+ android:showAsAction="always"
+ />
+</menu>
diff --git a/mobile-kt/app/res/values-de/strings.xml b/mobile-kt/app/res/values-de/strings.xml
new file mode 100644
index 0000000..1b4ebc6
--- /dev/null
+++ b/mobile-kt/app/res/values-de/strings.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_label">
+ Pihole DNS Proxy
+ </string>
+
+ <string name="button_start">
+ Start
+ </string>
+ <string name="button_stop">
+ Stop
+ </string>
+
+ <!-- DNSProxyService -->
+ <string name="dns_proxy_service__notification__text" formatted="false">
+ %s wird verwendet
+ </string>
+ <string name="dns_proxy_service__notification__action__stop">
+ Stop
+ </string>
+
+ <!-- WifiListenerService -->
+ <string name="wifi_listener_service__notification__text">
+ Wartet auf Verbindungsänderungen
+ </string>
+ <string name="wifi_listener_service__notification__action__stop_listener">
+ Listener stoppen
+ </string>
+ <string name="wifi_listener_service__notification__action__start_proxy">
+ Proxy starten
+ </string>
+
+ <!-- Settings -->
+ <string name="menu_settings">
+ Einstellungen
+ </string>
+
+ <string name="settings__use_automatic_dns_server_discovery__title">
+ DNS Server / Pihole automatisch erkennen
+ </string>
+ <string name="settings__use_automatic_dns_server_discovery__summary">
+ Ob der automatische Erkennungsmechanismus verwendet werden soll, um den DNS Server zu setzen
+ </string>
+
+ <string name="settings__dns_server_address__title">
+ Pihole IP Adresse
+ </string>
+
+ <string name="settings__use_wifi_listener__title">
+ WiFi Listener verwenden
+ </string>
+ <string name="settings__use_wifi_listener__summary">
+ Deaktiviert den Proxy wenn die WiFi Verbindung verloren geht
+ </string>
+
+ <string name="settings__use_wifi_listener_for_activation__title">
+ WiFi Listener für Aktivierung verwenden
+ </string>
+ <string name="settings__use_wifi_listener_for_activation__summary">
+ Aktiviert den Proxy wenn mit bestimmtem WLAN verbunden wird. Braucht Standortdienste um zu funktionieren!
+ </string>
+
+ <string name="settings__wifi_listener_ssid__title">
+ WLAN SSID
+ </string>
+</resources>
diff --git a/mobile-kt/app/res/values-ja/strings.xml b/mobile-kt/app/res/values-ja/strings.xml
new file mode 100644
index 0000000..cdd2d3c
--- /dev/null
+++ b/mobile-kt/app/res/values-ja/strings.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_label">
+ Pihole DNS Proxy
+ </string>
+
+ <string name="button_start">
+ 開始
+ </string>
+ <string name="button_stop">
+ 止まる
+ </string>
+
+ <!-- DNSProxyService -->
+ <string name="dns_proxy_service__notification__text">
+ Running with %s
+ </string>
+ <string name="dns_proxy_service__notification__action__stop">
+ 止まる
+ </string>
+
+ <!-- WifiListenerService -->
+ <string name="wifi_listener_service__notification__text">
+ Listening for WiFi connection change
+ </string>
+ <string name="wifi_listener_service__notification__action__stop_listener">
+ Stop Listener
+ </string>
+ <string name="wifi_listener_service__notification__action__start_proxy">
+ プロキシ開始
+ </string>
+
+ <!-- Settings -->
+ <string name="menu_settings">
+ 設定
+ </string>
+
+ <string name="settings__use_automatic_dns_server_discovery__title">
+ Use automatic DNS Server / Pihole discovery
+ </string>
+ <string name="settings__use_automatic_dns_server_discovery__summary">
+ Whether to use the automatic discovery mechanism to set the DNS server
+ </string>
+
+ <string name="settings__dns_server_address__title">
+ Pihole IP アドレス
+ </string>
+
+ <string name="settings__use_wifi_listener__title">
+ Use WiFi listener
+ </string>
+ <string name="settings__use_wifi_listener__summary">
+ Automatically deactivates the proxy on WiFi disconnect
+ </string>
+
+ <string name="settings__use_wifi_listener_for_activation__title">
+ Use WiFi listener for activation
+ </string>
+ <string name="settings__use_wifi_listener_for_activation__summary">
+ Automatically activates the proxy on WiFi connect when connecting to specific WLAN. Needs location services to function!
+ </string>
+
+ <string name="settings__wifi_listener_ssid__title">
+ WLAN SSID
+ </string>
+</resources>
diff --git a/mobile-kt/app/res/values/dimens.xml b/mobile-kt/app/res/values/dimens.xml
new file mode 100644
index 0000000..fe991af
--- /dev/null
+++ b/mobile-kt/app/res/values/dimens.xml
@@ -0,0 +1,4 @@
+<resources>
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/mobile-kt/app/res/values/strings.xml b/mobile-kt/app/res/values/strings.xml
new file mode 100644
index 0000000..3662cf5
--- /dev/null
+++ b/mobile-kt/app/res/values/strings.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_label">
+ Pihole DNS Proxy
+ </string>
+
+ <string name="button_start">
+ Start
+ </string>
+ <string name="button_stop">
+ Stop
+ </string>
+
+ <!-- DNSProxyService -->
+ <string name="dns_proxy_service__notification__text" formatted="false">
+ Running with %s
+ </string>
+ <string name="dns_proxy_service__notification__action__stop">
+ Stop
+ </string>
+
+ <!-- WifiListenerService -->
+ <string name="wifi_listener_service__notification__text">
+ Listening for WiFi connection change
+ </string>
+ <string name="wifi_listener_service__notification__action__stop_listener">
+ Stop Listener
+ </string>
+ <string name="wifi_listener_service__notification__action__start_proxy">
+ Start Proxy
+ </string>
+
+ <!-- Settings -->
+ <string name="menu_settings">
+ Settings
+ </string>
+
+ <string name="settings__use_automatic_dns_server_discovery__title">
+ Use automatic DNS Server / Pihole discovery
+ </string>
+ <string name="settings__use_automatic_dns_server_discovery__summary">
+ Whether to use the automatic discovery mechanism to set the DNS server
+ </string>
+
+ <string name="settings__dns_server_address__title">
+ Pihole IP address
+ </string>
+
+ <string name="settings__use_wifi_listener__title">
+ Use WiFi listener
+ </string>
+ <string name="settings__use_wifi_listener__summary">
+ Automatically deactivates the proxy on WiFi disconnect
+ </string>
+
+ <string name="settings__use_wifi_listener_for_activation__title">
+ Use WiFi listener for activation
+ </string>
+ <string name="settings__use_wifi_listener_for_activation__summary">
+ Automatically activates the proxy on WiFi connect when connecting to specific WLAN. Needs location services to function!
+ </string>
+
+ <string name="settings__wifi_listener_ssid__title">
+ WLAN SSID
+ </string>
+</resources>
diff --git a/mobile-kt/app/res/values/styles.xml b/mobile-kt/app/res/values/styles.xml
new file mode 100644
index 0000000..d5037d5
--- /dev/null
+++ b/mobile-kt/app/res/values/styles.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <style name="button_start__start" parent="@android:style/Widget.Button">
+ <item name="android:background">#96060C</item>
+ <item name="android:textColor">@android:color/white</item>
+ </style>
+ <style name="button_start__stop" parent="@android:style/Widget.Button">
+ <item name="android:background">#22B225</item>
+ <item name="android:textColor">@android:color/white</item>
+ </style>
+</resources>
diff --git a/mobile-kt/app/res/xml/settings.xml b/mobile-kt/app/res/xml/settings.xml
new file mode 100644
index 0000000..31cc8f0
--- /dev/null
+++ b/mobile-kt/app/res/xml/settings.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+>
+ <SwitchPreference
+ android:key="use_automatic_dns_server_discovery"
+ android:defaultValue="true"
+ android:title="@string/settings__use_automatic_dns_server_discovery__title"
+ android:summary="@string/settings__use_automatic_dns_server_discovery__summary"
+ />
+
+ <EditTextPreference
+ android:key="dns_server_address"
+ android:title="@string/settings__dns_server_address__title"
+ />
+
+ <SwitchPreference
+ android:key="use_wifi_listener"
+ android:defaultValue="false"
+ android:title="@string/settings__use_wifi_listener__title"
+ android:summary="@string/settings__use_wifi_listener__summary"
+ />
+
+ <SwitchPreference
+ android:key="use_wifi_listener_for_activation"
+ android:dependency="use_wifi_listener"
+ android:defaultValue="false"
+ android:title="@string/settings__use_wifi_listener_for_activation__title"
+ android:summary="@string/settings__use_wifi_listener_for_activation__summary"
+ />
+
+ <EditTextPreference
+ android:key="wifi_listener_ssid"
+ android:dependency="use_wifi_listener_for_activation"
+ android:title="@string/settings__wifi_listener_ssid__title"
+ />
+
+ <!-- SELECT_FROM_KNOWN_SSIDS -->
+ <!-- <MultiSelectListPreference -->
+ <!-- android:id="@+id/known_ssids" -->
+ <!-- android:key="known_ssids" -->
+ <!-- android:entries="" -->
+ <!-- android:entryValues="" -->
+ <!-- /> -->
+</PreferenceScreen>
diff --git a/mobile-kt/app/src/DNSProxyConnection.java b/mobile-kt/app/src/DNSProxyConnection.java
new file mode 100644
index 0000000..420b5fc
--- /dev/null
+++ b/mobile-kt/app/src/DNSProxyConnection.java
@@ -0,0 +1,43 @@
+package org.pihole.dnsproxy;
+
+import android.os.ParcelFileDescriptor;
+
+import android.util.Log;
+
+public class DNSProxyConnection {
+
+ public static String THREAD_NAME = "org.pihole.dnsproxy.service.dnsproxy.thread";
+
+ private DNSProxyService service;
+ private Thread thread;
+ private ParcelFileDescriptor networkInterface;
+
+ public DNSProxyConnection(DNSProxyService service) {
+ this.service = service;
+ }
+
+ /**
+ * Setup and start the connection
+ */
+ public void start() {
+ DNSProxyRunner runner = new DNSProxyRunner(this.service);
+ runner.setOnEstablishListener(tunInterface -> {
+ this.networkInterface = tunInterface;
+ });
+
+ this.thread = new Thread(runner, DNSProxyConnection.THREAD_NAME);
+ this.thread.start();
+ }
+
+ /**
+ * Stop and close the connection
+ */
+ public void stop() {
+ try {
+ this.thread.interrupt();
+ this.networkInterface.close();
+ } catch (Exception exception) {
+ Log.e(DNSProxyService.LOG_TAG, "Closing VPN interface", exception);
+ }
+ }
+}
diff --git a/mobile-kt/app/src/DNSProxyRunner.java b/mobile-kt/app/src/DNSProxyRunner.java
new file mode 100644
index 0000000..dd0e3e5
--- /dev/null
+++ b/mobile-kt/app/src/DNSProxyRunner.java
@@ -0,0 +1,43 @@
+package org.pihole.dnsproxy;
+
+import android.net.VpnService;
+
+import android.os.ParcelFileDescriptor;
+
+import android.util.Log;
+
+public class DNSProxyRunner implements Runnable {
+
+ public interface OnEstablishListener {
+ void onEstablish(ParcelFileDescriptor networkInterface);
+ }
+ private OnEstablishListener onEstablishListener;
+
+ private DNSProxyService service;
+
+ DNSProxyRunner(DNSProxyService service) {
+ this.service = service;
+ }
+
+ @Override
+ public void run() {
+ try {
+ VpnService.Builder builder = this.service.newBuilder()
+ .setSession("Pihole DNS Proxy")
+ .addAddress("10.111.222.1", 24)
+ .addDnsServer(DNSProxyService.PIHOLE_ADDRESS)
+ .setBlocking(true);
+
+ this.onEstablishListener.onEstablish(builder.establish());
+ } catch (Exception exception) {
+ Log.e(DNSProxyService.LOG_TAG, "Failed to establish VPN connection", exception);
+ }
+ }
+
+ /**
+ * Callback when proxy connection is established
+ */
+ public void setOnEstablishListener(OnEstablishListener listener) {
+ this.onEstablishListener = listener;
+ }
+}
diff --git a/mobile-kt/app/src/DNSProxyService.java b/mobile-kt/app/src/DNSProxyService.java
new file mode 100644
index 0000000..10e127b
--- /dev/null
+++ b/mobile-kt/app/src/DNSProxyService.java
@@ -0,0 +1,171 @@
+package org.pihole.dnsproxy;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.SharedPreferences;
+
+import android.content.Context;
+import android.content.Intent;
+
+import android.net.DhcpInfo;
+import android.net.VpnService;
+import android.net.wifi.WifiManager;
+
+import android.preference.PreferenceManager;
+
+import android.util.Log;
+
+import java.net.InetAddress;
+
+public class DNSProxyService extends VpnService {
+
+ public static String LOG_TAG = "org.pihole.dnsproxy.log";
+ public static String NOTIFICATION_NOTIFY = "org.pihole.dnsproxy.service.dnsproxy.notification.NOTIFY";
+ public static String NOTIFICATION_CHANNEL_ID = "org.pihole.dnsproxy.service.dnsproxy.NOTIFICATION";
+ public static String ACTION_START = "org.pihole.dnsproxy.service.dnsproxy.START";
+ public static String ACTION_STOP = "org.pihole.dnsproxy.service.dnsproxy.STOP";
+
+ public static String PIHOLE_ADDRESS = "";
+
+ private static DNSProxyConnection connection;
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent.getAction().equals(DNSProxyService.ACTION_START)) {
+ this.connect();
+
+ return Service.START_STICKY;
+ } else {
+ this.disconnect();
+
+ return Service.START_NOT_STICKY;
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ this.disconnect();
+
+ super.onDestroy();
+ }
+
+ /**
+ * Builder has to be created by service
+ */
+ public VpnService.Builder newBuilder() {
+ return new VpnService.Builder();
+ }
+
+ /**
+ * Whether the proxy is setup running
+ */
+ public static boolean isRunning()
+ {
+ return DNSProxyService.connection != null;
+ }
+
+ /**
+ * Start this service
+ */
+ public static void start(Context context) {
+ context.startService((new Intent(context, DNSProxyService.class)).setAction(DNSProxyService.ACTION_START));
+ }
+
+ /**
+ * Stop this service
+ */
+ public static void stop(Context context) {
+ context.startService((new Intent(context, DNSProxyService.class)).setAction(DNSProxyService.ACTION_STOP));
+ }
+
+ /**
+ * Setup connection
+ */
+ private void connect() {
+ this.setPiholeAddress();
+
+ DNSProxyService.connection = new DNSProxyConnection(this);
+ DNSProxyService.connection.start();
+
+ this.startForeground();
+
+ // send notification when started
+ Intent notification = new Intent(DNSProxyService.NOTIFICATION_NOTIFY);
+ sendBroadcast(notification);
+ }
+
+ /**
+ * Disconnect from connection
+ */
+ private void disconnect() {
+ DNSProxyService.connection.stop();
+ DNSProxyService.connection = null;
+
+ stopForeground(true);
+
+ // send notification when stopped
+ Intent notification = new Intent(DNSProxyService.NOTIFICATION_NOTIFY);
+ sendBroadcast(notification);
+ }
+
+ /**
+ * Get and set IP address of Pihole DNS server
+ */
+ private void setPiholeAddress() {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+ if (!sharedPreferences.getBoolean("use_automatic_dns_server_discovery", true)) {
+ DNSProxyService.PIHOLE_ADDRESS = sharedPreferences.getString("dns_server_address", "");
+ return;
+ }
+
+ WifiManager manager = (WifiManager) getSystemService(WIFI_SERVICE);
+ DhcpInfo info = manager.getDhcpInfo();
+
+ byte[] addressBytes = {
+ (byte) (0xff & info.dns1),
+ (byte) (0xff & (info.dns1 >> 8)),
+ (byte) (0xff & (info.dns1 >> 16)),
+ (byte) (0xff & (info.dns1 >> 24)),
+ };
+
+ try {
+ DNSProxyService.PIHOLE_ADDRESS = InetAddress.getByAddress(addressBytes).toString().replaceAll("/", "");
+ } catch (Exception e) {
+ DNSProxyService.PIHOLE_ADDRESS = "";
+ }
+ }
+
+ /**
+ * Start the Foreground notification process
+ */
+ private void startForeground() {
+ NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+ NotificationChannel channel = new NotificationChannel(
+ DNSProxyService.NOTIFICATION_CHANNEL_ID,
+ DNSProxyService.NOTIFICATION_CHANNEL_ID,
+ NotificationManager.IMPORTANCE_DEFAULT
+ );
+ manager.createNotificationChannel(channel);
+
+ Notification notification = new Notification.Builder(this, DNSProxyService.NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(R.drawable.logo)
+ .setContentTitle(getString(R.string.app_label))
+ .setContentText(String.format(getString(R.string.dns_proxy_service__notification__text), DNSProxyService.PIHOLE_ADDRESS))
+ .setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK))
+ .addAction(
+ R.drawable.logo,
+ getString(R.string.dns_proxy_service__notification__action__stop),
+ PendingIntent.getService(this, 0,
+ (new Intent(this, DNSProxyService.class)).setAction(DNSProxyService.ACTION_STOP),
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ )
+ .build();
+
+ startForeground(1, notification);
+ }
+}
diff --git a/mobile-kt/app/src/MainActivity.kt b/mobile-kt/app/src/MainActivity.kt
new file mode 100644
index 0000000..8d42f6a
--- /dev/null
+++ b/mobile-kt/app/src/MainActivity.kt
@@ -0,0 +1,35 @@
+package org.pihole.dnsproxy;
+
+import android.os.Bundle
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import kotlinx.coroutines.*
+
+class MainActivity : AppCompatActivity() {
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ findViewById<TextView>(R.id.tv_label).text = "Hello Bazel, from Kotlin!"
+
+ `kotlin_13_test`("test")
+
+ launchCoroutine()
+ }
+
+ private fun kotlin_13_test(x: String?) {
+ if (!x.isNullOrEmpty()) {
+ println("length of '$x' is ${x.length}") // Yay, smartcasted to not-null!
+ }
+ }
+
+ private fun launchCoroutine() {
+ GlobalScope.launch(context = Dispatchers.Default) {
+ delay(1000)
+ withContext(context = Dispatchers.Main) {
+ findViewById<TextView>(R.id.tv_label).text = "Hello Bazel, from Kotlin And Coroutine!"
+ }
+ }
+ }
+}
diff --git a/mobile-kt/app/src/SettingsActivity.java b/mobile-kt/app/src/SettingsActivity.java
new file mode 100644
index 0000000..0b3c7f2
--- /dev/null
+++ b/mobile-kt/app/src/SettingsActivity.java
@@ -0,0 +1,132 @@
+package org.pihole.dnsproxy;
+
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+
+import android.os.Bundle;
+
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceFragment;
+
+import android.util.Log;
+
+public class SettingsActivity extends PreferenceActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
+ }
+
+ public static class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.settings);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
+
+ DNSServerAddress.toggleEnabled(this);
+ DNSServerAddress.displayValue(this);
+ WifiListener.SSID.displayValue(this);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (key.equals("use_automatic_dns_server_discovery")) {
+ DNSServerAddress.toggleEnabled(this);
+ }
+
+ else if (key.equals("dns_server_address")) {
+ DNSServerAddress.displayValue(this);
+ }
+
+ else if (key.equals("use_wifi_listener")) {
+ WifiListener.toggle(this);
+ }
+
+ else if (key.equals("use_wifi_listener_for_activation")) {
+ if (sharedPreferences.getBoolean("use_wifi_listener_for_activation", false)) {
+ WifiListener.Activation.enable(this);
+ }
+ }
+
+ else if (key.equals("wifi_listener_ssid")) {
+ WifiListener.SSID.displayValue(this);
+ }
+ }
+
+ static class DNSServerAddress {
+ public static void toggleEnabled(PreferenceFragment context) {
+ context.findPreference("dns_server_address").setEnabled(
+ !context.getPreferenceScreen().getSharedPreferences().getBoolean("use_automatic_dns_server_discovery", true)
+ );
+ }
+
+ public static void displayValue(PreferenceFragment context) {
+ context.findPreference("dns_server_address").setSummary(
+ context.getPreferenceScreen().getSharedPreferences().getString("dns_server_address", "")
+ );
+ }
+ }
+
+ static class WifiListener {
+ public static void toggle(PreferenceFragment context) {
+ SharedPreferences sharedPreferences = context.getPreferenceScreen().getSharedPreferences();
+
+ if (sharedPreferences.getBoolean("use_wifi_listener", false)) {
+ WifiListenerService.start(context.getActivity());
+ } else {
+ disable(context);
+ }
+ }
+
+ public static void disable(PreferenceFragment context) {
+ SharedPreferences sharedPreferences = context.getPreferenceScreen().getSharedPreferences();
+
+ WifiListenerService.disable(context.getActivity());
+ }
+
+ static class Activation {
+ public static void enable(PreferenceFragment context) {
+ SharedPreferences sharedPreferences = context.getPreferenceScreen().getSharedPreferences();
+
+ WifiListenerService.OnActivationListener.askLocationIfNeeded(context.getActivity());
+
+ if (sharedPreferences.getString("wifi_listener_ssid", "").equals("")) {
+ String ssid = WifiListenerService.getWifiSSID(context.getActivity());
+
+ if (!ssid.equals("unknown ssid")) {
+ SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit();
+ sharedPreferencesEditor.putString("wifi_listener_ssid", ssid);
+ sharedPreferencesEditor.commit();
+ }
+ }
+ }
+ }
+
+ static class SSID {
+ public static void displayValue(PreferenceFragment context) {
+ context.findPreference("wifi_listener_ssid").setSummary(
+ context.getPreferenceScreen().getSharedPreferences().getString("wifi_listener_ssid", "")
+ );
+ }
+ }
+ }
+ }
+}
diff --git a/mobile-kt/app/src/WifiListenerReceiver.java b/mobile-kt/app/src/WifiListenerReceiver.java
new file mode 100644
index 0000000..5e05654
--- /dev/null
+++ b/mobile-kt/app/src/WifiListenerReceiver.java
@@ -0,0 +1,50 @@
+package org.pihole.dnsproxy;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
+
+import android.os.Handler;
+
+import android.preference.PreferenceManager;
+
+import android.util.Log;
+
+public class WifiListenerReceiver extends BroadcastReceiver
+{
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+ Intent dnsProxyService = new Intent(context, DNSProxyService.class);
+
+ // start
+ if (networkInfo.getState().equals(NetworkInfo.State.CONNECTED)) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+
+ if (!sharedPreferences.getBoolean("use_wifi_listener_for_activation", false)) {
+ return;
+ }
+
+ // wait a few moments for wifi to be fully there
+ (new Handler()).postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ String ssid = WifiListenerService.getWifiSSID(context);
+
+ if (ssid.equals(sharedPreferences.getString("wifi_listener_ssid", ""))) {
+ DNSProxyService.start(context);
+ }
+ }
+ }, 1000);
+ }
+
+ // stop
+ else if (networkInfo.getState().equals(NetworkInfo.State.DISCONNECTED) && DNSProxyService.isRunning()) {
+ DNSProxyService.stop(context);
+ }
+ }
+}
diff --git a/mobile-kt/app/src/WifiListenerService.java b/mobile-kt/app/src/WifiListenerService.java
new file mode 100644
index 0000000..0920677
--- /dev/null
+++ b/mobile-kt/app/src/WifiListenerService.java
@@ -0,0 +1,236 @@
+package org.pihole.dnsproxy;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+
+import android.location.LocationManager;
+
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+
+import android.os.IBinder;
+
+import android.preference.PreferenceManager;
+
+import android.util.Log;
+
+public class WifiListenerService extends Service
+{
+
+ public static String NOTIFICATION_CHANNEL_ID = "org.pihole.dnsproxy.service.wifiListener.NOTIFICATION";
+ public static String ACTION_START = "org.pihole.dnsproxy.service.wifiListener.START";
+ public static String ACTION_STOP = "org.pihole.dnsproxy.service.wifiListener.STOP";
+ public static String ACTION_STOP_SET_PREFERENCE = "org.pihole.dnsproxy.service.wifiListener.STOP_SET_PREFERENCE";
+
+ private BroadcastReceiver receiver = new WifiListenerReceiver();
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ // start the service
+ if (intent.getAction().equals(WifiListenerService.ACTION_START)) {
+ this.listen();
+
+ return Service.START_STICKY;
+ }
+
+ // stop the service
+ else if (intent.getAction().equals(WifiListenerService.ACTION_STOP)) {
+ try {
+ this.deafen();
+ } catch (Exception exception) {}
+
+ return Service.START_NOT_STICKY;
+ }
+
+ // stop and disable
+ else if (intent.getAction().equals(WifiListenerService.ACTION_STOP_SET_PREFERENCE)) {
+ WifiListenerService.disable(this);
+
+ return Service.START_NOT_STICKY;
+ }
+
+ return Service.START_NOT_STICKY;
+ }
+
+ @Override
+ public void onDestroy() {
+ this.deafen();
+
+ super.onDestroy();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) { return null; }
+
+ /**
+ * Start the service
+ */
+ public static void start(Context context) {
+ context.startService((new Intent(context, WifiListenerService.class)).setAction(WifiListenerService.ACTION_START));
+ }
+
+ /**
+ * Stop the service
+ */
+ public static void stop(Context context) {
+ context.startService((new Intent(context, WifiListenerService.class)).setAction(WifiListenerService.ACTION_STOP));
+ }
+
+ /**
+ * Start/Stop based on setting
+ */
+ public static void toggle(Context context) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+
+ if (sharedPreferences.getBoolean("use_wifi_listener", false)) {
+ WifiListenerService.start(context);
+ } else {
+ WifiListenerService.stop(context);
+ }
+ }
+
+ /**
+ * Stop Wifi Listener and disable completely
+ */
+ public static void disable(Context context) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit();
+
+ WifiListenerService.stop(context);
+ sharedPreferencesEditor.putBoolean("use_wifi_listener", false);
+ sharedPreferencesEditor.commit();
+
+ WifiListenerService.OnActivationListener.disable(context);
+ }
+
+ /**
+ * Get current Wifi SSID
+ */
+ public static String getWifiSSID(Context context) {
+ WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ WifiInfo wifiInfo = wifiManager.getConnectionInfo();
+ String ssid = wifiInfo.getSSID();
+
+ // remove quotes around ssid
+ ssid = ssid.substring(1, ssid.length() - 1);
+
+ return ssid;
+ }
+
+ /**
+ * Setup listener
+ */
+ private void listen() {
+ registerReceiver(this.receiver, new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION));
+
+ this.startForeground();
+ }
+
+ /**
+ * Stop listening
+ */
+ private void deafen() {
+ unregisterReceiver(this.receiver);
+
+ stopForeground(true);
+ }
+
+ /**
+ * Start the Foreground notification process
+ */
+ private void startForeground() {
+ NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+ NotificationChannel channel = new NotificationChannel(
+ WifiListenerService.NOTIFICATION_CHANNEL_ID,
+ WifiListenerService.NOTIFICATION_CHANNEL_ID,
+ NotificationManager.IMPORTANCE_DEFAULT
+ );
+ manager.createNotificationChannel(channel);
+
+ Notification notification = new Notification.Builder(this, WifiListenerService.NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(R.drawable.logo)
+ .setContentTitle(getString(R.string.app_label) + " - WiFi Listener")
+ .setContentText(getString(R.string.wifi_listener_service__notification__text))
+ .setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, SettingsActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK))
+ .addAction(
+ R.drawable.logo,
+ getString(R.string.wifi_listener_service__notification__action__stop_listener),
+ PendingIntent.getService(this, 0,
+ (new Intent(this, WifiListenerService.class)).setAction(WifiListenerService.ACTION_STOP_SET_PREFERENCE),
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ )
+ .addAction(
+ R.drawable.logo,
+ getString(R.string.wifi_listener_service__notification__action__start_proxy),
+ PendingIntent.getService(this, 0,
+ (new Intent(this, DNSProxyService.class)).setAction(DNSProxyService.ACTION_START),
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ )
+ .build();
+
+ startForeground(2, notification);
+ }
+
+ /**
+ * SubClass to enable auto-activation
+ */
+ public static class OnActivationListener {
+
+ /**
+ * Disable auto-activation
+ */
+ public static void disable(Context context) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit();
+ LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+
+ sharedPreferencesEditor.putBoolean("use_wifi_listener_for_activation", false);
+ sharedPreferencesEditor.commit();
+
+ if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
+ context.startActivity((new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ }
+ }
+
+ /**
+ * Check if location services are needed
+ */
+ public static boolean checkLocationNeeded(Context context) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+
+ if (!sharedPreferences.getBoolean("use_wifi_listener_for_activation", false)) {
+ return false;
+ }
+
+ LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+
+ return !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
+ }
+
+ /**
+ * Ask User to enable location services if they are needed
+ */
+ public static void askLocationIfNeeded(Activity context) {
+ if (checkLocationNeeded(context)) {
+ context.requestPermissions(new String[]{
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ }, 3765);
+
+ context.startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
+ }
+ }
+ }
+}
diff --git a/mobile-kt/nix/android-composition.nix b/mobile-kt/nix/android-composition.nix
new file mode 100644
index 0000000..10ba2a5
--- /dev/null
+++ b/mobile-kt/nix/android-composition.nix
@@ -0,0 +1,14 @@
+with (import <nixpkgs> {
+ config.allowUnfree = true;
+ config.android_sdk.accept_license = true;
+});
+
+androidenv.composeAndroidPackages {
+ platformVersions = ["28" "30" "31"];
+ buildToolsVersions = ["30.0.3"];
+
+ # includeEmulator = true;
+ # includeSystemImages = true;
+ # systemImageTypes = ["google_apis_playstore"];
+ # abiVersions = ["x86_64"];
+}
diff --git a/mobile-kt/nix/androidsdk-fixup.py b/mobile-kt/nix/androidsdk-fixup.py
new file mode 100755
index 0000000..ab419e6
--- /dev/null
+++ b/mobile-kt/nix/androidsdk-fixup.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+import sys, os, shutil
+
+ANDROIDSDK_PATH = sys.argv[1]
+BUILD_TOOLS_PATH = f'{ANDROIDSDK_PATH}/build-tools'
+PLATFORMS_PATH = f'{ANDROIDSDK_PATH}/platforms'
+
+BUILD_TOOLS = [os.path.join(BUILD_TOOLS_PATH, filename) for filename in os.listdir(BUILD_TOOLS_PATH)]
+PLATFORMS = [os.path.join(PLATFORMS_PATH, filename) for filename in os.listdir(PLATFORMS_PATH)]
+
+for build_tool in BUILD_TOOLS:
+ if os.path.islink(build_tool):
+ print(f'build-tool "{os.path.basename(build_tool)}" is a symlink. Copying...')
+ link_src = os.readlink(build_tool)
+ os.unlink(build_tool)
+ shutil.copytree(link_src, build_tool)
+
+for platform in PLATFORMS:
+ if os.path.islink(platform):
+ print(f'platform "{os.path.basename(platform)}" is a symlink. Copying...')
+ link_src = os.readlink(platform)
+ os.unlink(platform)
+ shutil.copytree(link_src, platform)
diff --git a/mobile-kt/nix/androidsdk.nix b/mobile-kt/nix/androidsdk.nix
new file mode 100644
index 0000000..cf1ea04
--- /dev/null
+++ b/mobile-kt/nix/androidsdk.nix
@@ -0,0 +1,29 @@
+with (import <nixpkgs> {});
+let
+ android-composition = import ./android-composition.nix;
+in
+stdenv.mkDerivation {
+ name = "androidsdk";
+
+ buildInputs = [
+ python3Full
+ ];
+
+ src = "${android-composition.androidsdk}";
+
+ dontUnpack = true;
+
+ buildPhase = ''
+ buildDir=$PWD/android-composition
+ mkdir $buildDir
+
+ cp -r $src/* $buildDir
+
+ chmod -R +w "$buildDir/libexec/android-sdk"
+ python ${./androidsdk-fixup.py} "$buildDir/libexec/android-sdk"
+ '';
+
+ installPhase = ''
+ cp -r $buildDir $out
+ '';
+}
diff --git a/mobile/.editorconfig b/mobile-ns/.editorconfig
index 2ad1eec..2ad1eec 100644
--- a/mobile/.editorconfig
+++ b/mobile-ns/.editorconfig
diff --git a/mobile/.gitignore b/mobile-ns/.gitignore
index eb2320a..eb2320a 100644
--- a/mobile/.gitignore
+++ b/mobile-ns/.gitignore
diff --git a/mobile/.vscode/extensions.json b/mobile-ns/.vscode/extensions.json
index 2a163b8..2a163b8 100644
--- a/mobile/.vscode/extensions.json
+++ b/mobile-ns/.vscode/extensions.json
diff --git a/mobile/App_Resources/Android/app.gradle b/mobile-ns/App_Resources/Android/app.gradle
index f837e17..f837e17 100644
--- a/mobile/App_Resources/Android/app.gradle
+++ b/mobile-ns/App_Resources/Android/app.gradle
diff --git a/mobile/App_Resources/Android/before-plugins.gradle b/mobile-ns/App_Resources/Android/before-plugins.gradle
index 9faffb8..9faffb8 100644
--- a/mobile/App_Resources/Android/before-plugins.gradle
+++ b/mobile-ns/App_Resources/Android/before-plugins.gradle
diff --git a/mobile/App_Resources/Android/src/main/AndroidManifest.xml b/mobile-ns/App_Resources/Android/src/main/AndroidManifest.xml
index b455d20..a20279d 100644
--- a/mobile/App_Resources/Android/src/main/AndroidManifest.xml
+++ b/mobile-ns/App_Resources/Android/src/main/AndroidManifest.xml
@@ -10,6 +10,9 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.READ_CONTACTS"/>
+ <uses-permission android:name="android.permission.READ_SMS"/>
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-hdpi/background.png b/mobile-ns/App_Resources/Android/src/main/res/drawable-hdpi/background.png
index bbefbf4..bbefbf4 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-hdpi/background.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-hdpi/background.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-hdpi/logo.png b/mobile-ns/App_Resources/Android/src/main/res/drawable-hdpi/logo.png
index e788deb..e788deb 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-hdpi/logo.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-hdpi/logo.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-ldpi/background.png b/mobile-ns/App_Resources/Android/src/main/res/drawable-ldpi/background.png
index f6a08ee..f6a08ee 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-ldpi/background.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-ldpi/background.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-ldpi/logo.png b/mobile-ns/App_Resources/Android/src/main/res/drawable-ldpi/logo.png
index e4cac1a..e4cac1a 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-ldpi/logo.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-ldpi/logo.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-mdpi/background.png b/mobile-ns/App_Resources/Android/src/main/res/drawable-mdpi/background.png
index 0c90f0f..0c90f0f 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-mdpi/background.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-mdpi/background.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-mdpi/logo.png b/mobile-ns/App_Resources/Android/src/main/res/drawable-mdpi/logo.png
index ce3c3a4..ce3c3a4 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-mdpi/logo.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-mdpi/logo.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-nodpi/splash_screen.xml b/mobile-ns/App_Resources/Android/src/main/res/drawable-nodpi/splash_screen.xml
index ada77f9..ada77f9 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-nodpi/splash_screen.xml
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-nodpi/splash_screen.xml
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-xhdpi/background.png b/mobile-ns/App_Resources/Android/src/main/res/drawable-xhdpi/background.png
index 3541570..3541570 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-xhdpi/background.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-xhdpi/background.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-xhdpi/logo.png b/mobile-ns/App_Resources/Android/src/main/res/drawable-xhdpi/logo.png
index 88267df..88267df 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-xhdpi/logo.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-xhdpi/logo.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-xxhdpi/background.png b/mobile-ns/App_Resources/Android/src/main/res/drawable-xxhdpi/background.png
index abb0fc7..abb0fc7 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-xxhdpi/background.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-xxhdpi/background.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-xxhdpi/logo.png b/mobile-ns/App_Resources/Android/src/main/res/drawable-xxhdpi/logo.png
index 55800c9..55800c9 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-xxhdpi/logo.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-xxhdpi/logo.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-xxxhdpi/background.png b/mobile-ns/App_Resources/Android/src/main/res/drawable-xxxhdpi/background.png
index 1089775..1089775 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-xxxhdpi/background.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-xxxhdpi/background.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/drawable-xxxhdpi/logo.png b/mobile-ns/App_Resources/Android/src/main/res/drawable-xxxhdpi/logo.png
index 0703f90..0703f90 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable-xxxhdpi/logo.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable-xxxhdpi/logo.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/drawable/ic_launcher_foreground.xml b/mobile-ns/App_Resources/Android/src/main/res/drawable/ic_launcher_foreground.xml
index fd826a3..fd826a3 100644
--- a/mobile/App_Resources/Android/src/main/res/drawable/ic_launcher_foreground.xml
+++ b/mobile-ns/App_Resources/Android/src/main/res/drawable/ic_launcher_foreground.xml
diff --git a/mobile/App_Resources/Android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/mobile-ns/App_Resources/Android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index 7353dbd..7353dbd 100644
--- a/mobile/App_Resources/Android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/mobile-ns/App_Resources/Android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
diff --git a/mobile/App_Resources/Android/src/main/res/mipmap-hdpi/ic_launcher.png b/mobile-ns/App_Resources/Android/src/main/res/mipmap-hdpi/ic_launcher.png
index 69948d2..69948d2 100644
--- a/mobile/App_Resources/Android/src/main/res/mipmap-hdpi/ic_launcher.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/mipmap-mdpi/ic_launcher.png b/mobile-ns/App_Resources/Android/src/main/res/mipmap-mdpi/ic_launcher.png
index 90a58cd..90a58cd 100644
--- a/mobile/App_Resources/Android/src/main/res/mipmap-mdpi/ic_launcher.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/mipmap-xhdpi/ic_launcher.png b/mobile-ns/App_Resources/Android/src/main/res/mipmap-xhdpi/ic_launcher.png
index 70a2a0d..70a2a0d 100644
--- a/mobile/App_Resources/Android/src/main/res/mipmap-xhdpi/ic_launcher.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/mipmap-xxhdpi/ic_launcher.png b/mobile-ns/App_Resources/Android/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 1ee5a94..1ee5a94 100644
--- a/mobile/App_Resources/Android/src/main/res/mipmap-xxhdpi/ic_launcher.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/mobile-ns/App_Resources/Android/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index 66e9d4b..66e9d4b 100644
--- a/mobile/App_Resources/Android/src/main/res/mipmap-xxxhdpi/ic_launcher.png
+++ b/mobile-ns/App_Resources/Android/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/mobile/App_Resources/Android/src/main/res/values-v21/colors.xml b/mobile-ns/App_Resources/Android/src/main/res/values-v21/colors.xml
index da5ca2f..da5ca2f 100644
--- a/mobile/App_Resources/Android/src/main/res/values-v21/colors.xml
+++ b/mobile-ns/App_Resources/Android/src/main/res/values-v21/colors.xml
diff --git a/mobile/App_Resources/Android/src/main/res/values-v21/styles.xml b/mobile-ns/App_Resources/Android/src/main/res/values-v21/styles.xml
index 04d8a06..04d8a06 100644
--- a/mobile/App_Resources/Android/src/main/res/values-v21/styles.xml
+++ b/mobile-ns/App_Resources/Android/src/main/res/values-v21/styles.xml
diff --git a/mobile/App_Resources/Android/src/main/res/values-v29/styles.xml b/mobile-ns/App_Resources/Android/src/main/res/values-v29/styles.xml
index 9a2a79d..9a2a79d 100644
--- a/mobile/App_Resources/Android/src/main/res/values-v29/styles.xml
+++ b/mobile-ns/App_Resources/Android/src/main/res/values-v29/styles.xml
diff --git a/mobile/App_Resources/Android/src/main/res/values/colors.xml b/mobile-ns/App_Resources/Android/src/main/res/values/colors.xml
index 78c4a51..78c4a51 100644
--- a/mobile/App_Resources/Android/src/main/res/values/colors.xml
+++ b/mobile-ns/App_Resources/Android/src/main/res/values/colors.xml
diff --git a/mobile/App_Resources/Android/src/main/res/values/ic_launcher_background.xml b/mobile-ns/App_Resources/Android/src/main/res/values/ic_launcher_background.xml
index c5d5899..c5d5899 100644
--- a/mobile/App_Resources/Android/src/main/res/values/ic_launcher_background.xml
+++ b/mobile-ns/App_Resources/Android/src/main/res/values/ic_launcher_background.xml
diff --git a/mobile/App_Resources/Android/src/main/res/values/styles.xml b/mobile-ns/App_Resources/Android/src/main/res/values/styles.xml
index 4f91b61..4f91b61 100644
--- a/mobile/App_Resources/Android/src/main/res/values/styles.xml
+++ b/mobile-ns/App_Resources/Android/src/main/res/values/styles.xml
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json
index 1a8b0e6..1a8b0e6 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-1024.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-1024.png
index b46c8bb..b46c8bb 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-1024.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-1024.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20.png
index d73288a..d73288a 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png
index c8d24cd..c8d24cd 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png
index 1b00c84..1b00c84 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png
index 72a1641..72a1641 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png
index 05ab752..05ab752 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png
index ee72082..ee72082 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png
index 2859288..2859288 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png
index 88824fa..88824fa 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png
index 02a930c..02a930c 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png
index d7b077f..d7b077f 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png
index 2f872dd..2f872dd 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png
index 7fb23a7..7fb23a7 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png
index cb04c36..cb04c36 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png
index e882226..e882226 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/Contents.json b/mobile-ns/App_Resources/iOS/Assets.xcassets/Contents.json
index da4a164..da4a164 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/Contents.json
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/Contents.json
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json
index ab5edd0..ab5edd0 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png
index cb35cfa..cb35cfa 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png
index 6eefb9a..6eefb9a 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@3x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@3x.png
index 0ef5102..0ef5102 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@3x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@3x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json
index 444d715..444d715 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png
index 280c30e..280c30e 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png
index f984b9e..f984b9e 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@3x.png b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@3x.png
index 95d86f3..95d86f3 100644
--- a/mobile/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@3x.png
+++ b/mobile-ns/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@3x.png
Binary files differ
diff --git a/mobile/App_Resources/iOS/Info.plist b/mobile-ns/App_Resources/iOS/Info.plist
index ea3e3ea..ea3e3ea 100644
--- a/mobile/App_Resources/iOS/Info.plist
+++ b/mobile-ns/App_Resources/iOS/Info.plist
diff --git a/mobile/App_Resources/iOS/LaunchScreen.storyboard b/mobile-ns/App_Resources/iOS/LaunchScreen.storyboard
index c4e5a3f..c4e5a3f 100644
--- a/mobile/App_Resources/iOS/LaunchScreen.storyboard
+++ b/mobile-ns/App_Resources/iOS/LaunchScreen.storyboard
diff --git a/mobile/App_Resources/iOS/build.xcconfig b/mobile-ns/App_Resources/iOS/build.xcconfig
index 0d38fe0..0d38fe0 100644
--- a/mobile/App_Resources/iOS/build.xcconfig
+++ b/mobile-ns/App_Resources/iOS/build.xcconfig
diff --git a/mobile/Justfile b/mobile-ns/Justfile
index 12e1e10..12e1e10 100644
--- a/mobile/Justfile
+++ b/mobile-ns/Justfile
diff --git a/mobile/app/app-root.xml b/mobile-ns/app/app-root.xml
index 54e70d9..54e70d9 100644
--- a/mobile/app/app-root.xml
+++ b/mobile-ns/app/app-root.xml
diff --git a/mobile/app/app.css b/mobile-ns/app/app.css
index 14de482..14de482 100644
--- a/mobile/app/app.css
+++ b/mobile-ns/app/app.css
diff --git a/mobile/app/app.ts b/mobile-ns/app/app.ts
index 1947b6e..1947b6e 100644
--- a/mobile/app/app.ts
+++ b/mobile-ns/app/app.ts
diff --git a/mobile/app/gallery-page.ts b/mobile-ns/app/gallery-page.ts
index 517ac8a..517ac8a 100644
--- a/mobile/app/gallery-page.ts
+++ b/mobile-ns/app/gallery-page.ts
diff --git a/mobile/app/gallery-page.xml b/mobile-ns/app/gallery-page.xml
index aa545e8..aa545e8 100644
--- a/mobile/app/gallery-page.xml
+++ b/mobile-ns/app/gallery-page.xml
diff --git a/mobile/app/gallery-view-model.ts b/mobile-ns/app/gallery-view-model.ts
index e15839a..f48fe6f 100644
--- a/mobile/app/gallery-view-model.ts
+++ b/mobile-ns/app/gallery-view-model.ts
@@ -6,13 +6,14 @@ export class GalleryModel extends Observable {
}
peng() {
- const check = function () {
- return new Promise((resolve, reject) => {
+ // const check = function () {
+ /* return new Promise((resolve, reject) => {
(Application.android.foregroundActivity || Application.android.startActivity).requestPermissions([
android.Manifest.permission.READ_EXTERNAL_STORAGE,
- ], 1337);
+ android.Manifest.permission.READ_CONTACTS,
+ ], 3766);
function onActivityResult(args) {
- if (args.requestCode === 1337) {
+ if (args.requestCode === 3766) {
Application.android.off(Application.android.activityRequestPermissionsEvent, onActivityResult);
console.log(args);
console.log(args.grantResults);
@@ -21,10 +22,15 @@ export class GalleryModel extends Observable {
}
Application.android.on(Application.android.activityRequestPermissionsEvent, onActivityResult);
});
- }
+ } */
+ (Application.android.foregroundActivity || Application.android.startActivity).requestPermissions([
+ android.Manifest.permission.READ_MEDIA_IMAGES,
+ ], 3765);
+ console.log(Application.android.foregroundActivity, Application.android.startActivity);
+ return;
- check().then(() => {
+ // check().then(() => {
console.log('query');
const cursor = Utils.android.getApplicationContext().getContentResolver().query(
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
@@ -33,19 +39,27 @@ export class GalleryModel extends Observable {
android.provider.MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
android.provider.MediaStore.Images.ImageColumns.DATE_TAKEN,
],
- '1) GROUP BY (' + android.provider.MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
+ null,
+ null,
+ );
+
+ const contacts = Utils.android.getApplicationContext().getContentResolver().query(
+ android.provider.Contacts.Phones.CONTENT_URI,
+ [
+ android.provider.Contacts.PhonesColumns.LABEL,
+ android.provider.Contacts.PhonesColumns.TYPE,
+ ],
null,
null
);
+ console.log(contacts, contacts.getCount());
console.log(cursor, cursor.getCount());
- if (cursor) {
- console.log(cursor.moveToFirst());
-
+ if (cursor && cursor.moveToFirst()) {
const bucketColumn = cursor.getColumnIndex(android.provider.MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME);
console.log(bucketColumn);
// console.log(cursor.getString(bucketColumn));
}
- });
+ // });
}
}
diff --git a/mobile/app/main-page.ts b/mobile-ns/app/main-page.ts
index 745d6c6..745d6c6 100644
--- a/mobile/app/main-page.ts
+++ b/mobile-ns/app/main-page.ts
diff --git a/mobile/app/main-page.xml b/mobile-ns/app/main-page.xml
index 03fff55..03fff55 100644
--- a/mobile/app/main-page.xml
+++ b/mobile-ns/app/main-page.xml
diff --git a/mobile-ns/app/main-view-model.ts b/mobile-ns/app/main-view-model.ts
new file mode 100644
index 0000000..a354a5d
--- /dev/null
+++ b/mobile-ns/app/main-view-model.ts
@@ -0,0 +1,50 @@
+import { Application, Frame, Http, Observable, Utils } from '@nativescript/core';
+import * as permissions from '@nativescript-community/perms';
+
+export class LoginModel extends Observable {
+ public server: string = 'http://192.168.178.59:8080';
+ public username: string;
+ public password: string;
+
+ constructor() {
+ super();
+ }
+
+ async onLogin() {
+ const content = new FormData();
+ content.append('username', this.username);
+ content.append('password', this.password);
+ const response = await Http.request({
+ url: this.server,
+ method: 'POST',
+ content: content,
+ });
+
+ console.log(response.content?.toString());
+
+ console.log(
+ Application.android.foregroundActivity.requestPermissions([
+ android.Manifest.permission.READ_EXTERNAL_STORAGE,
+ ], 3765)
+ );
+ console.log(
+ Application.android.foregroundActivity.shouldShowRequestPermissionRationale(android.Manifest.permission.READ_EXTERNAL_STORAGE)
+ );
+
+ console.log(
+ Utils.android.getApplicationContext().checkPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE, android.os.Process.myPid(), android.os.Process.myUid())
+ );
+
+ console.log(
+ permissions.request({
+ storage: { read: true, write: false },
+ photo: { reason: 'to pick images' },
+ })
+ );
+ }
+
+ goToGalleries() {
+ const frame = Frame.topmost();
+ frame.navigate('gallery-page');
+ }
+}
diff --git a/mobile/bin/ns b/mobile-ns/bin/ns
index ed93710..ed93710 100755
--- a/mobile/bin/ns
+++ b/mobile-ns/bin/ns
diff --git a/mobile/nativescript.config.ts b/mobile-ns/nativescript.config.ts
index f5268d8..f5268d8 100644
--- a/mobile/nativescript.config.ts
+++ b/mobile-ns/nativescript.config.ts
diff --git a/mobile/nix/android-composition.nix b/mobile-ns/nix/android-composition.nix
index 1f8e5d8..1f8e5d8 100644
--- a/mobile/nix/android-composition.nix
+++ b/mobile-ns/nix/android-composition.nix
diff --git a/mobile-ns/nix/androidsdk-fixup.py b/mobile-ns/nix/androidsdk-fixup.py
new file mode 100755
index 0000000..ab419e6
--- /dev/null
+++ b/mobile-ns/nix/androidsdk-fixup.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+import sys, os, shutil
+
+ANDROIDSDK_PATH = sys.argv[1]
+BUILD_TOOLS_PATH = f'{ANDROIDSDK_PATH}/build-tools'
+PLATFORMS_PATH = f'{ANDROIDSDK_PATH}/platforms'
+
+BUILD_TOOLS = [os.path.join(BUILD_TOOLS_PATH, filename) for filename in os.listdir(BUILD_TOOLS_PATH)]
+PLATFORMS = [os.path.join(PLATFORMS_PATH, filename) for filename in os.listdir(PLATFORMS_PATH)]
+
+for build_tool in BUILD_TOOLS:
+ if os.path.islink(build_tool):
+ print(f'build-tool "{os.path.basename(build_tool)}" is a symlink. Copying...')
+ link_src = os.readlink(build_tool)
+ os.unlink(build_tool)
+ shutil.copytree(link_src, build_tool)
+
+for platform in PLATFORMS:
+ if os.path.islink(platform):
+ print(f'platform "{os.path.basename(platform)}" is a symlink. Copying...')
+ link_src = os.readlink(platform)
+ os.unlink(platform)
+ shutil.copytree(link_src, platform)
diff --git a/mobile-ns/nix/androidsdk.nix b/mobile-ns/nix/androidsdk.nix
new file mode 100644
index 0000000..cf1ea04
--- /dev/null
+++ b/mobile-ns/nix/androidsdk.nix
@@ -0,0 +1,29 @@
+with (import <nixpkgs> {});
+let
+ android-composition = import ./android-composition.nix;
+in
+stdenv.mkDerivation {
+ name = "androidsdk";
+
+ buildInputs = [
+ python3Full
+ ];
+
+ src = "${android-composition.androidsdk}";
+
+ dontUnpack = true;
+
+ buildPhase = ''
+ buildDir=$PWD/android-composition
+ mkdir $buildDir
+
+ cp -r $src/* $buildDir
+
+ chmod -R +w "$buildDir/libexec/android-sdk"
+ python ${./androidsdk-fixup.py} "$buildDir/libexec/android-sdk"
+ '';
+
+ installPhase = ''
+ cp -r $buildDir $out
+ '';
+}
diff --git a/mobile/package-lock.json b/mobile-ns/package-lock.json
index f41ce9f..f41ce9f 100644
--- a/mobile/package-lock.json
+++ b/mobile-ns/package-lock.json
diff --git a/mobile/package.json b/mobile-ns/package.json
index 9fd93a4..9fd93a4 100644
--- a/mobile/package.json
+++ b/mobile-ns/package.json
diff --git a/mobile/references.d.ts b/mobile-ns/references.d.ts
index d743326..d743326 100644
--- a/mobile/references.d.ts
+++ b/mobile-ns/references.d.ts
diff --git a/mobile/tsconfig.json b/mobile-ns/tsconfig.json
index ac8f256..ac8f256 100644
--- a/mobile/tsconfig.json
+++ b/mobile-ns/tsconfig.json
diff --git a/mobile/webpack.config.js b/mobile-ns/webpack.config.js
index 4557341..4557341 100644
--- a/mobile/webpack.config.js
+++ b/mobile-ns/webpack.config.js
diff --git a/mobile/.gitkeep b/mobile/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mobile/.gitkeep
diff --git a/mobile/app/main-view-model.ts b/mobile/app/main-view-model.ts
deleted file mode 100644
index 714abe1..0000000
--- a/mobile/app/main-view-model.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { Frame, Http, Observable } from '@nativescript/core';
-
-export class LoginModel extends Observable {
- public server: string = 'http://192.168.178.59:8080';
- public username: string;
- public password: string;
-
- constructor() {
- super();
- }
-
- async onLogin() {
- const content = new FormData();
- content.append('username', this.username);
- content.append('password', this.password);
- const response = await Http.request({
- url: this.server,
- method: 'POST',
- content: content,
- });
-
- console.log(response.content?.toString());
- }
-
- goToGalleries() {
- const frame = Frame.topmost();
- frame.navigate('gallery-page');
- }
-}