diff options
-rw-r--r-- | mobile-gradle/.gitattributes | 9 | ||||
-rw-r--r-- | mobile-gradle/.gitignore | 5 | ||||
-rw-r--r-- | mobile-gradle/Justfile | 0 | ||||
-rw-r--r-- | mobile-gradle/build.gradle.kts | 6 | ||||
-rw-r--r-- | mobile-gradle/gradle/libs.versions.toml | 2 | ||||
-rw-r--r-- | mobile-gradle/gradle/wrapper/gradle-wrapper.jar | bin | 0 -> 43462 bytes | |||
-rw-r--r-- | mobile-gradle/gradle/wrapper/gradle-wrapper.properties | 7 | ||||
-rwxr-xr-x | mobile-gradle/gradlew | 249 | ||||
-rw-r--r-- | mobile-gradle/gradlew.bat | 92 | ||||
-rw-r--r-- | mobile-gradle/nix/android-composition.nix | 14 | ||||
-rwxr-xr-x | mobile-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.kts | 8 | ||||
-rw-r--r-- | mobile-kt/.gitignore | 2 | ||||
-rw-r--r-- | mobile-kt/Makefile | 17 | ||||
-rw-r--r-- | mobile-kt/WORKSPACE | 25 | ||||
-rw-r--r-- | mobile-kt/app/AndroidManifest.xml | 54 | ||||
-rw-r--r-- | mobile-kt/app/BUILD | 18 | ||||
-rw-r--r-- | mobile-kt/app/res/drawable/logo.png | bin | 0 -> 8963 bytes | |||
-rw-r--r-- | mobile-kt/app/res/layout/main.xml | 43 | ||||
-rw-r--r-- | mobile-kt/app/res/menu/settings.xml | 11 | ||||
-rw-r--r-- | mobile-kt/app/res/values-de/strings.xml | 66 | ||||
-rw-r--r-- | mobile-kt/app/res/values-ja/strings.xml | 66 | ||||
-rw-r--r-- | mobile-kt/app/res/values/dimens.xml | 4 | ||||
-rw-r--r-- | mobile-kt/app/res/values/strings.xml | 66 | ||||
-rw-r--r-- | mobile-kt/app/res/values/styles.xml | 11 | ||||
-rw-r--r-- | mobile-kt/app/res/xml/settings.xml | 45 | ||||
-rw-r--r-- | mobile-kt/app/src/DNSProxyConnection.java | 43 | ||||
-rw-r--r-- | mobile-kt/app/src/DNSProxyRunner.java | 43 | ||||
-rw-r--r-- | mobile-kt/app/src/DNSProxyService.java | 171 | ||||
-rw-r--r-- | mobile-kt/app/src/MainActivity.kt | 35 | ||||
-rw-r--r-- | mobile-kt/app/src/SettingsActivity.java | 132 | ||||
-rw-r--r-- | mobile-kt/app/src/WifiListenerReceiver.java | 50 | ||||
-rw-r--r-- | mobile-kt/app/src/WifiListenerService.java | 236 | ||||
-rw-r--r-- | mobile-kt/nix/android-composition.nix | 14 | ||||
-rwxr-xr-x | mobile-kt/nix/androidsdk-fixup.py | 24 | ||||
-rw-r--r-- | mobile-kt/nix/androidsdk.nix | 29 | ||||
-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) | bin | 3661 -> 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) | bin | 5165 -> 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) | bin | 1609 -> 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) | bin | 2511 -> 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) | bin | 2218 -> 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) | bin | 3432 -> 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) | bin | 5473 -> 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) | bin | 6904 -> 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) | bin | 9949 -> 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) | bin | 10319 -> 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) | bin | 15701 -> 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) | bin | 13941 -> 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) | bin | 3092 -> 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) | bin | 1956 -> 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) | bin | 4484 -> 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) | bin | 7184 -> 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) | bin | 10378 -> 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) | bin | 17868 -> 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) | bin | 745 -> 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) | bin | 995 -> 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) | bin | 1258 -> 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) | bin | 851 -> 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) | bin | 1232 -> 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) | bin | 1668 -> 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) | bin | 995 -> 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) | bin | 1504 -> 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) | bin | 2121 -> 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) | bin | 2121 -> 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) | bin | 3018 -> 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) | bin | 1482 -> 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) | bin | 2633 -> 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) | bin | 2831 -> 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) | bin | 4920 -> 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) | bin | 14165 -> 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) | bin | 27892 -> 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) | bin | 6808 -> 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) | bin | 13502 -> 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) | bin | 20794 -> 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.ts | 50 | ||||
-rwxr-xr-x | mobile-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-x | mobile-ns/nix/androidsdk-fixup.py | 24 | ||||
-rw-r--r-- | mobile-ns/nix/androidsdk.nix | 29 | ||||
-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/.gitkeep | 0 | ||||
-rw-r--r-- | mobile/app/main-view-model.ts | 29 |
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 Binary files differnew file mode 100644 index 0000000..d64cd49 --- /dev/null +++ b/mobile-gradle/gradle/wrapper/gradle-wrapper.jar 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 Binary files differnew file mode 100644 index 0000000..154b579 --- /dev/null +++ b/mobile-kt/app/res/drawable/logo.png 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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 Binary files differindex 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 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'); - } -} |