summaryrefslogtreecommitdiff
path: root/mobile-kt/app
diff options
context:
space:
mode:
authorDaniel Weipert <git@mail.dweipert.de>2024-01-26 14:51:36 +0100
committerDaniel Weipert <git@mail.dweipert.de>2024-01-26 14:52:57 +0100
commitd3bf2d09f740221771806789b00bf915c9f5f2e3 (patch)
tree95f99eabd763dff1907f107393504ee75aa747d7 /mobile-kt/app
parent466d03a38cb01e9ff9a2d11be113a81c2bdce34a (diff)
initial commitHEADmain
Diffstat (limited to 'mobile-kt/app')
-rw-r--r--mobile-kt/app/AndroidManifest.xml54
-rw-r--r--mobile-kt/app/BUILD18
-rw-r--r--mobile-kt/app/res/drawable/logo.pngbin0 -> 8963 bytes
-rw-r--r--mobile-kt/app/res/layout/main.xml43
-rw-r--r--mobile-kt/app/res/menu/settings.xml11
-rw-r--r--mobile-kt/app/res/values-de/strings.xml66
-rw-r--r--mobile-kt/app/res/values-ja/strings.xml66
-rw-r--r--mobile-kt/app/res/values/dimens.xml4
-rw-r--r--mobile-kt/app/res/values/strings.xml66
-rw-r--r--mobile-kt/app/res/values/styles.xml11
-rw-r--r--mobile-kt/app/res/xml/settings.xml45
-rw-r--r--mobile-kt/app/src/DNSProxyConnection.java43
-rw-r--r--mobile-kt/app/src/DNSProxyRunner.java43
-rw-r--r--mobile-kt/app/src/DNSProxyService.java171
-rw-r--r--mobile-kt/app/src/MainActivity.kt35
-rw-r--r--mobile-kt/app/src/SettingsActivity.java132
-rw-r--r--mobile-kt/app/src/WifiListenerReceiver.java50
-rw-r--r--mobile-kt/app/src/WifiListenerService.java236
18 files changed, 1094 insertions, 0 deletions
diff --git a/mobile-kt/app/AndroidManifest.xml b/mobile-kt/app/AndroidManifest.xml
new file mode 100644
index 0000000..0c417b7
--- /dev/null
+++ b/mobile-kt/app/AndroidManifest.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="org.image-sync"
+ android:versionCode="1"
+ android:versionName="1.0.0"
+>
+ <uses-sdk
+ android:minSdkVersion="28"
+ android:targetSdkVersion="30"
+ />
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_SMS" />
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
+
+ <application
+ android:icon="@drawable/logo"
+ android:usesCleartextTraffic="true"
+ >
+ <!-- <service
+ android:name=".WifiListenerService"
+ android:foregroundServiceType="location"
+ ></service> -->
+
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_label"
+ android:screenOrientation="portrait"
+ >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <!-- <activity
+ android:name=".SettingsActivity"
+ android:label="@string/menu_settings"
+ android:parentActivityName=".MainActivity">
+
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".MainActivity"
+ />
+ </activity> -->
+ </application>
+</manifest>
diff --git a/mobile-kt/app/BUILD b/mobile-kt/app/BUILD
new file mode 100644
index 0000000..c3e38c2
--- /dev/null
+++ b/mobile-kt/app/BUILD
@@ -0,0 +1,18 @@
+android_library(
+ name = "main",
+ manifest = "AndroidManifest.xml",
+ resource_files = glob(["res/**"]),
+)
+
+load("@rules_kotlin//kotlin:android.bzl", "kt_android_library")
+kt_android_library(
+ name = "main_kt",
+ srcs = glob(["src/*.kt"]),
+ deps = [":main"],
+)
+
+android_binary(
+ name = "image-sync",
+ manifest = "AndroidManifest.xml",
+ deps = [":main", ":main_kt"],
+)
diff --git a/mobile-kt/app/res/drawable/logo.png b/mobile-kt/app/res/drawable/logo.png
new file mode 100644
index 0000000..154b579
--- /dev/null
+++ b/mobile-kt/app/res/drawable/logo.png
Binary files differ
diff --git a/mobile-kt/app/res/layout/main.xml b/mobile-kt/app/res/layout/main.xml
new file mode 100644
index 0000000..d3bbcf5
--- /dev/null
+++ b/mobile-kt/app/res/layout/main.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:orientation="vertical"
+ tools:context=".MainActivity"
+>
+
+ <TextureView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/surface_view"
+ />
+
+ <Button
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/button_start"
+ android:layout_gravity="center"
+ android:onClick="onClickButtonStart"
+ android:text="@string/button_start"
+ android:background="#22B225"
+ android:textColor="@android:color/white"
+ android:textSize="96sp"
+ />
+ <Button
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/button_stop"
+ android:layout_gravity="center"
+ android:onClick="onClickButtonStop"
+ android:text="@string/button_stop"
+ android:background="#96060C"
+ android:textColor="@android:color/white"
+ android:textSize="96sp"
+ />
+</FrameLayout>
diff --git a/mobile-kt/app/res/menu/settings.xml b/mobile-kt/app/res/menu/settings.xml
new file mode 100644
index 0000000..3e3bcbb
--- /dev/null
+++ b/mobile-kt/app/res/menu/settings.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu
+ xmlns:android="http://schemas.android.com/apk/res/android"
+>
+ <item
+ android:id="@+id/menu_settings"
+ android:icon="@android:drawable/ic_menu_preferences"
+ android:title="@string/menu_settings"
+ android:showAsAction="always"
+ />
+</menu>
diff --git a/mobile-kt/app/res/values-de/strings.xml b/mobile-kt/app/res/values-de/strings.xml
new file mode 100644
index 0000000..1b4ebc6
--- /dev/null
+++ b/mobile-kt/app/res/values-de/strings.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_label">
+ Pihole DNS Proxy
+ </string>
+
+ <string name="button_start">
+ Start
+ </string>
+ <string name="button_stop">
+ Stop
+ </string>
+
+ <!-- DNSProxyService -->
+ <string name="dns_proxy_service__notification__text" formatted="false">
+ %s wird verwendet
+ </string>
+ <string name="dns_proxy_service__notification__action__stop">
+ Stop
+ </string>
+
+ <!-- WifiListenerService -->
+ <string name="wifi_listener_service__notification__text">
+ Wartet auf Verbindungsänderungen
+ </string>
+ <string name="wifi_listener_service__notification__action__stop_listener">
+ Listener stoppen
+ </string>
+ <string name="wifi_listener_service__notification__action__start_proxy">
+ Proxy starten
+ </string>
+
+ <!-- Settings -->
+ <string name="menu_settings">
+ Einstellungen
+ </string>
+
+ <string name="settings__use_automatic_dns_server_discovery__title">
+ DNS Server / Pihole automatisch erkennen
+ </string>
+ <string name="settings__use_automatic_dns_server_discovery__summary">
+ Ob der automatische Erkennungsmechanismus verwendet werden soll, um den DNS Server zu setzen
+ </string>
+
+ <string name="settings__dns_server_address__title">
+ Pihole IP Adresse
+ </string>
+
+ <string name="settings__use_wifi_listener__title">
+ WiFi Listener verwenden
+ </string>
+ <string name="settings__use_wifi_listener__summary">
+ Deaktiviert den Proxy wenn die WiFi Verbindung verloren geht
+ </string>
+
+ <string name="settings__use_wifi_listener_for_activation__title">
+ WiFi Listener für Aktivierung verwenden
+ </string>
+ <string name="settings__use_wifi_listener_for_activation__summary">
+ Aktiviert den Proxy wenn mit bestimmtem WLAN verbunden wird. Braucht Standortdienste um zu funktionieren!
+ </string>
+
+ <string name="settings__wifi_listener_ssid__title">
+ WLAN SSID
+ </string>
+</resources>
diff --git a/mobile-kt/app/res/values-ja/strings.xml b/mobile-kt/app/res/values-ja/strings.xml
new file mode 100644
index 0000000..cdd2d3c
--- /dev/null
+++ b/mobile-kt/app/res/values-ja/strings.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_label">
+ Pihole DNS Proxy
+ </string>
+
+ <string name="button_start">
+ 開始
+ </string>
+ <string name="button_stop">
+ 止まる
+ </string>
+
+ <!-- DNSProxyService -->
+ <string name="dns_proxy_service__notification__text">
+ Running with %s
+ </string>
+ <string name="dns_proxy_service__notification__action__stop">
+ 止まる
+ </string>
+
+ <!-- WifiListenerService -->
+ <string name="wifi_listener_service__notification__text">
+ Listening for WiFi connection change
+ </string>
+ <string name="wifi_listener_service__notification__action__stop_listener">
+ Stop Listener
+ </string>
+ <string name="wifi_listener_service__notification__action__start_proxy">
+ プロキシ開始
+ </string>
+
+ <!-- Settings -->
+ <string name="menu_settings">
+ 設定
+ </string>
+
+ <string name="settings__use_automatic_dns_server_discovery__title">
+ Use automatic DNS Server / Pihole discovery
+ </string>
+ <string name="settings__use_automatic_dns_server_discovery__summary">
+ Whether to use the automatic discovery mechanism to set the DNS server
+ </string>
+
+ <string name="settings__dns_server_address__title">
+ Pihole IP アドレス
+ </string>
+
+ <string name="settings__use_wifi_listener__title">
+ Use WiFi listener
+ </string>
+ <string name="settings__use_wifi_listener__summary">
+ Automatically deactivates the proxy on WiFi disconnect
+ </string>
+
+ <string name="settings__use_wifi_listener_for_activation__title">
+ Use WiFi listener for activation
+ </string>
+ <string name="settings__use_wifi_listener_for_activation__summary">
+ Automatically activates the proxy on WiFi connect when connecting to specific WLAN. Needs location services to function!
+ </string>
+
+ <string name="settings__wifi_listener_ssid__title">
+ WLAN SSID
+ </string>
+</resources>
diff --git a/mobile-kt/app/res/values/dimens.xml b/mobile-kt/app/res/values/dimens.xml
new file mode 100644
index 0000000..fe991af
--- /dev/null
+++ b/mobile-kt/app/res/values/dimens.xml
@@ -0,0 +1,4 @@
+<resources>
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/mobile-kt/app/res/values/strings.xml b/mobile-kt/app/res/values/strings.xml
new file mode 100644
index 0000000..3662cf5
--- /dev/null
+++ b/mobile-kt/app/res/values/strings.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_label">
+ Pihole DNS Proxy
+ </string>
+
+ <string name="button_start">
+ Start
+ </string>
+ <string name="button_stop">
+ Stop
+ </string>
+
+ <!-- DNSProxyService -->
+ <string name="dns_proxy_service__notification__text" formatted="false">
+ Running with %s
+ </string>
+ <string name="dns_proxy_service__notification__action__stop">
+ Stop
+ </string>
+
+ <!-- WifiListenerService -->
+ <string name="wifi_listener_service__notification__text">
+ Listening for WiFi connection change
+ </string>
+ <string name="wifi_listener_service__notification__action__stop_listener">
+ Stop Listener
+ </string>
+ <string name="wifi_listener_service__notification__action__start_proxy">
+ Start Proxy
+ </string>
+
+ <!-- Settings -->
+ <string name="menu_settings">
+ Settings
+ </string>
+
+ <string name="settings__use_automatic_dns_server_discovery__title">
+ Use automatic DNS Server / Pihole discovery
+ </string>
+ <string name="settings__use_automatic_dns_server_discovery__summary">
+ Whether to use the automatic discovery mechanism to set the DNS server
+ </string>
+
+ <string name="settings__dns_server_address__title">
+ Pihole IP address
+ </string>
+
+ <string name="settings__use_wifi_listener__title">
+ Use WiFi listener
+ </string>
+ <string name="settings__use_wifi_listener__summary">
+ Automatically deactivates the proxy on WiFi disconnect
+ </string>
+
+ <string name="settings__use_wifi_listener_for_activation__title">
+ Use WiFi listener for activation
+ </string>
+ <string name="settings__use_wifi_listener_for_activation__summary">
+ Automatically activates the proxy on WiFi connect when connecting to specific WLAN. Needs location services to function!
+ </string>
+
+ <string name="settings__wifi_listener_ssid__title">
+ WLAN SSID
+ </string>
+</resources>
diff --git a/mobile-kt/app/res/values/styles.xml b/mobile-kt/app/res/values/styles.xml
new file mode 100644
index 0000000..d5037d5
--- /dev/null
+++ b/mobile-kt/app/res/values/styles.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <style name="button_start__start" parent="@android:style/Widget.Button">
+ <item name="android:background">#96060C</item>
+ <item name="android:textColor">@android:color/white</item>
+ </style>
+ <style name="button_start__stop" parent="@android:style/Widget.Button">
+ <item name="android:background">#22B225</item>
+ <item name="android:textColor">@android:color/white</item>
+ </style>
+</resources>
diff --git a/mobile-kt/app/res/xml/settings.xml b/mobile-kt/app/res/xml/settings.xml
new file mode 100644
index 0000000..31cc8f0
--- /dev/null
+++ b/mobile-kt/app/res/xml/settings.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+>
+ <SwitchPreference
+ android:key="use_automatic_dns_server_discovery"
+ android:defaultValue="true"
+ android:title="@string/settings__use_automatic_dns_server_discovery__title"
+ android:summary="@string/settings__use_automatic_dns_server_discovery__summary"
+ />
+
+ <EditTextPreference
+ android:key="dns_server_address"
+ android:title="@string/settings__dns_server_address__title"
+ />
+
+ <SwitchPreference
+ android:key="use_wifi_listener"
+ android:defaultValue="false"
+ android:title="@string/settings__use_wifi_listener__title"
+ android:summary="@string/settings__use_wifi_listener__summary"
+ />
+
+ <SwitchPreference
+ android:key="use_wifi_listener_for_activation"
+ android:dependency="use_wifi_listener"
+ android:defaultValue="false"
+ android:title="@string/settings__use_wifi_listener_for_activation__title"
+ android:summary="@string/settings__use_wifi_listener_for_activation__summary"
+ />
+
+ <EditTextPreference
+ android:key="wifi_listener_ssid"
+ android:dependency="use_wifi_listener_for_activation"
+ android:title="@string/settings__wifi_listener_ssid__title"
+ />
+
+ <!-- SELECT_FROM_KNOWN_SSIDS -->
+ <!-- <MultiSelectListPreference -->
+ <!-- android:id="@+id/known_ssids" -->
+ <!-- android:key="known_ssids" -->
+ <!-- android:entries="" -->
+ <!-- android:entryValues="" -->
+ <!-- /> -->
+</PreferenceScreen>
diff --git a/mobile-kt/app/src/DNSProxyConnection.java b/mobile-kt/app/src/DNSProxyConnection.java
new file mode 100644
index 0000000..420b5fc
--- /dev/null
+++ b/mobile-kt/app/src/DNSProxyConnection.java
@@ -0,0 +1,43 @@
+package org.pihole.dnsproxy;
+
+import android.os.ParcelFileDescriptor;
+
+import android.util.Log;
+
+public class DNSProxyConnection {
+
+ public static String THREAD_NAME = "org.pihole.dnsproxy.service.dnsproxy.thread";
+
+ private DNSProxyService service;
+ private Thread thread;
+ private ParcelFileDescriptor networkInterface;
+
+ public DNSProxyConnection(DNSProxyService service) {
+ this.service = service;
+ }
+
+ /**
+ * Setup and start the connection
+ */
+ public void start() {
+ DNSProxyRunner runner = new DNSProxyRunner(this.service);
+ runner.setOnEstablishListener(tunInterface -> {
+ this.networkInterface = tunInterface;
+ });
+
+ this.thread = new Thread(runner, DNSProxyConnection.THREAD_NAME);
+ this.thread.start();
+ }
+
+ /**
+ * Stop and close the connection
+ */
+ public void stop() {
+ try {
+ this.thread.interrupt();
+ this.networkInterface.close();
+ } catch (Exception exception) {
+ Log.e(DNSProxyService.LOG_TAG, "Closing VPN interface", exception);
+ }
+ }
+}
diff --git a/mobile-kt/app/src/DNSProxyRunner.java b/mobile-kt/app/src/DNSProxyRunner.java
new file mode 100644
index 0000000..dd0e3e5
--- /dev/null
+++ b/mobile-kt/app/src/DNSProxyRunner.java
@@ -0,0 +1,43 @@
+package org.pihole.dnsproxy;
+
+import android.net.VpnService;
+
+import android.os.ParcelFileDescriptor;
+
+import android.util.Log;
+
+public class DNSProxyRunner implements Runnable {
+
+ public interface OnEstablishListener {
+ void onEstablish(ParcelFileDescriptor networkInterface);
+ }
+ private OnEstablishListener onEstablishListener;
+
+ private DNSProxyService service;
+
+ DNSProxyRunner(DNSProxyService service) {
+ this.service = service;
+ }
+
+ @Override
+ public void run() {
+ try {
+ VpnService.Builder builder = this.service.newBuilder()
+ .setSession("Pihole DNS Proxy")
+ .addAddress("10.111.222.1", 24)
+ .addDnsServer(DNSProxyService.PIHOLE_ADDRESS)
+ .setBlocking(true);
+
+ this.onEstablishListener.onEstablish(builder.establish());
+ } catch (Exception exception) {
+ Log.e(DNSProxyService.LOG_TAG, "Failed to establish VPN connection", exception);
+ }
+ }
+
+ /**
+ * Callback when proxy connection is established
+ */
+ public void setOnEstablishListener(OnEstablishListener listener) {
+ this.onEstablishListener = listener;
+ }
+}
diff --git a/mobile-kt/app/src/DNSProxyService.java b/mobile-kt/app/src/DNSProxyService.java
new file mode 100644
index 0000000..10e127b
--- /dev/null
+++ b/mobile-kt/app/src/DNSProxyService.java
@@ -0,0 +1,171 @@
+package org.pihole.dnsproxy;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.SharedPreferences;
+
+import android.content.Context;
+import android.content.Intent;
+
+import android.net.DhcpInfo;
+import android.net.VpnService;
+import android.net.wifi.WifiManager;
+
+import android.preference.PreferenceManager;
+
+import android.util.Log;
+
+import java.net.InetAddress;
+
+public class DNSProxyService extends VpnService {
+
+ public static String LOG_TAG = "org.pihole.dnsproxy.log";
+ public static String NOTIFICATION_NOTIFY = "org.pihole.dnsproxy.service.dnsproxy.notification.NOTIFY";
+ public static String NOTIFICATION_CHANNEL_ID = "org.pihole.dnsproxy.service.dnsproxy.NOTIFICATION";
+ public static String ACTION_START = "org.pihole.dnsproxy.service.dnsproxy.START";
+ public static String ACTION_STOP = "org.pihole.dnsproxy.service.dnsproxy.STOP";
+
+ public static String PIHOLE_ADDRESS = "";
+
+ private static DNSProxyConnection connection;
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent.getAction().equals(DNSProxyService.ACTION_START)) {
+ this.connect();
+
+ return Service.START_STICKY;
+ } else {
+ this.disconnect();
+
+ return Service.START_NOT_STICKY;
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ this.disconnect();
+
+ super.onDestroy();
+ }
+
+ /**
+ * Builder has to be created by service
+ */
+ public VpnService.Builder newBuilder() {
+ return new VpnService.Builder();
+ }
+
+ /**
+ * Whether the proxy is setup running
+ */
+ public static boolean isRunning()
+ {
+ return DNSProxyService.connection != null;
+ }
+
+ /**
+ * Start this service
+ */
+ public static void start(Context context) {
+ context.startService((new Intent(context, DNSProxyService.class)).setAction(DNSProxyService.ACTION_START));
+ }
+
+ /**
+ * Stop this service
+ */
+ public static void stop(Context context) {
+ context.startService((new Intent(context, DNSProxyService.class)).setAction(DNSProxyService.ACTION_STOP));
+ }
+
+ /**
+ * Setup connection
+ */
+ private void connect() {
+ this.setPiholeAddress();
+
+ DNSProxyService.connection = new DNSProxyConnection(this);
+ DNSProxyService.connection.start();
+
+ this.startForeground();
+
+ // send notification when started
+ Intent notification = new Intent(DNSProxyService.NOTIFICATION_NOTIFY);
+ sendBroadcast(notification);
+ }
+
+ /**
+ * Disconnect from connection
+ */
+ private void disconnect() {
+ DNSProxyService.connection.stop();
+ DNSProxyService.connection = null;
+
+ stopForeground(true);
+
+ // send notification when stopped
+ Intent notification = new Intent(DNSProxyService.NOTIFICATION_NOTIFY);
+ sendBroadcast(notification);
+ }
+
+ /**
+ * Get and set IP address of Pihole DNS server
+ */
+ private void setPiholeAddress() {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+ if (!sharedPreferences.getBoolean("use_automatic_dns_server_discovery", true)) {
+ DNSProxyService.PIHOLE_ADDRESS = sharedPreferences.getString("dns_server_address", "");
+ return;
+ }
+
+ WifiManager manager = (WifiManager) getSystemService(WIFI_SERVICE);
+ DhcpInfo info = manager.getDhcpInfo();
+
+ byte[] addressBytes = {
+ (byte) (0xff & info.dns1),
+ (byte) (0xff & (info.dns1 >> 8)),
+ (byte) (0xff & (info.dns1 >> 16)),
+ (byte) (0xff & (info.dns1 >> 24)),
+ };
+
+ try {
+ DNSProxyService.PIHOLE_ADDRESS = InetAddress.getByAddress(addressBytes).toString().replaceAll("/", "");
+ } catch (Exception e) {
+ DNSProxyService.PIHOLE_ADDRESS = "";
+ }
+ }
+
+ /**
+ * Start the Foreground notification process
+ */
+ private void startForeground() {
+ NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+ NotificationChannel channel = new NotificationChannel(
+ DNSProxyService.NOTIFICATION_CHANNEL_ID,
+ DNSProxyService.NOTIFICATION_CHANNEL_ID,
+ NotificationManager.IMPORTANCE_DEFAULT
+ );
+ manager.createNotificationChannel(channel);
+
+ Notification notification = new Notification.Builder(this, DNSProxyService.NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(R.drawable.logo)
+ .setContentTitle(getString(R.string.app_label))
+ .setContentText(String.format(getString(R.string.dns_proxy_service__notification__text), DNSProxyService.PIHOLE_ADDRESS))
+ .setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK))
+ .addAction(
+ R.drawable.logo,
+ getString(R.string.dns_proxy_service__notification__action__stop),
+ PendingIntent.getService(this, 0,
+ (new Intent(this, DNSProxyService.class)).setAction(DNSProxyService.ACTION_STOP),
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ )
+ .build();
+
+ startForeground(1, notification);
+ }
+}
diff --git a/mobile-kt/app/src/MainActivity.kt b/mobile-kt/app/src/MainActivity.kt
new file mode 100644
index 0000000..8d42f6a
--- /dev/null
+++ b/mobile-kt/app/src/MainActivity.kt
@@ -0,0 +1,35 @@
+package org.pihole.dnsproxy;
+
+import android.os.Bundle
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import kotlinx.coroutines.*
+
+class MainActivity : AppCompatActivity() {
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ findViewById<TextView>(R.id.tv_label).text = "Hello Bazel, from Kotlin!"
+
+ `kotlin_13_test`("test")
+
+ launchCoroutine()
+ }
+
+ private fun kotlin_13_test(x: String?) {
+ if (!x.isNullOrEmpty()) {
+ println("length of '$x' is ${x.length}") // Yay, smartcasted to not-null!
+ }
+ }
+
+ private fun launchCoroutine() {
+ GlobalScope.launch(context = Dispatchers.Default) {
+ delay(1000)
+ withContext(context = Dispatchers.Main) {
+ findViewById<TextView>(R.id.tv_label).text = "Hello Bazel, from Kotlin And Coroutine!"
+ }
+ }
+ }
+}
diff --git a/mobile-kt/app/src/SettingsActivity.java b/mobile-kt/app/src/SettingsActivity.java
new file mode 100644
index 0000000..0b3c7f2
--- /dev/null
+++ b/mobile-kt/app/src/SettingsActivity.java
@@ -0,0 +1,132 @@
+package org.pihole.dnsproxy;
+
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+
+import android.os.Bundle;
+
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceFragment;
+
+import android.util.Log;
+
+public class SettingsActivity extends PreferenceActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
+ }
+
+ public static class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.settings);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
+
+ DNSServerAddress.toggleEnabled(this);
+ DNSServerAddress.displayValue(this);
+ WifiListener.SSID.displayValue(this);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (key.equals("use_automatic_dns_server_discovery")) {
+ DNSServerAddress.toggleEnabled(this);
+ }
+
+ else if (key.equals("dns_server_address")) {
+ DNSServerAddress.displayValue(this);
+ }
+
+ else if (key.equals("use_wifi_listener")) {
+ WifiListener.toggle(this);
+ }
+
+ else if (key.equals("use_wifi_listener_for_activation")) {
+ if (sharedPreferences.getBoolean("use_wifi_listener_for_activation", false)) {
+ WifiListener.Activation.enable(this);
+ }
+ }
+
+ else if (key.equals("wifi_listener_ssid")) {
+ WifiListener.SSID.displayValue(this);
+ }
+ }
+
+ static class DNSServerAddress {
+ public static void toggleEnabled(PreferenceFragment context) {
+ context.findPreference("dns_server_address").setEnabled(
+ !context.getPreferenceScreen().getSharedPreferences().getBoolean("use_automatic_dns_server_discovery", true)
+ );
+ }
+
+ public static void displayValue(PreferenceFragment context) {
+ context.findPreference("dns_server_address").setSummary(
+ context.getPreferenceScreen().getSharedPreferences().getString("dns_server_address", "")
+ );
+ }
+ }
+
+ static class WifiListener {
+ public static void toggle(PreferenceFragment context) {
+ SharedPreferences sharedPreferences = context.getPreferenceScreen().getSharedPreferences();
+
+ if (sharedPreferences.getBoolean("use_wifi_listener", false)) {
+ WifiListenerService.start(context.getActivity());
+ } else {
+ disable(context);
+ }
+ }
+
+ public static void disable(PreferenceFragment context) {
+ SharedPreferences sharedPreferences = context.getPreferenceScreen().getSharedPreferences();
+
+ WifiListenerService.disable(context.getActivity());
+ }
+
+ static class Activation {
+ public static void enable(PreferenceFragment context) {
+ SharedPreferences sharedPreferences = context.getPreferenceScreen().getSharedPreferences();
+
+ WifiListenerService.OnActivationListener.askLocationIfNeeded(context.getActivity());
+
+ if (sharedPreferences.getString("wifi_listener_ssid", "").equals("")) {
+ String ssid = WifiListenerService.getWifiSSID(context.getActivity());
+
+ if (!ssid.equals("unknown ssid")) {
+ SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit();
+ sharedPreferencesEditor.putString("wifi_listener_ssid", ssid);
+ sharedPreferencesEditor.commit();
+ }
+ }
+ }
+ }
+
+ static class SSID {
+ public static void displayValue(PreferenceFragment context) {
+ context.findPreference("wifi_listener_ssid").setSummary(
+ context.getPreferenceScreen().getSharedPreferences().getString("wifi_listener_ssid", "")
+ );
+ }
+ }
+ }
+ }
+}
diff --git a/mobile-kt/app/src/WifiListenerReceiver.java b/mobile-kt/app/src/WifiListenerReceiver.java
new file mode 100644
index 0000000..5e05654
--- /dev/null
+++ b/mobile-kt/app/src/WifiListenerReceiver.java
@@ -0,0 +1,50 @@
+package org.pihole.dnsproxy;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
+
+import android.os.Handler;
+
+import android.preference.PreferenceManager;
+
+import android.util.Log;
+
+public class WifiListenerReceiver extends BroadcastReceiver
+{
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+ Intent dnsProxyService = new Intent(context, DNSProxyService.class);
+
+ // start
+ if (networkInfo.getState().equals(NetworkInfo.State.CONNECTED)) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+
+ if (!sharedPreferences.getBoolean("use_wifi_listener_for_activation", false)) {
+ return;
+ }
+
+ // wait a few moments for wifi to be fully there
+ (new Handler()).postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ String ssid = WifiListenerService.getWifiSSID(context);
+
+ if (ssid.equals(sharedPreferences.getString("wifi_listener_ssid", ""))) {
+ DNSProxyService.start(context);
+ }
+ }
+ }, 1000);
+ }
+
+ // stop
+ else if (networkInfo.getState().equals(NetworkInfo.State.DISCONNECTED) && DNSProxyService.isRunning()) {
+ DNSProxyService.stop(context);
+ }
+ }
+}
diff --git a/mobile-kt/app/src/WifiListenerService.java b/mobile-kt/app/src/WifiListenerService.java
new file mode 100644
index 0000000..0920677
--- /dev/null
+++ b/mobile-kt/app/src/WifiListenerService.java
@@ -0,0 +1,236 @@
+package org.pihole.dnsproxy;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+
+import android.location.LocationManager;
+
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+
+import android.os.IBinder;
+
+import android.preference.PreferenceManager;
+
+import android.util.Log;
+
+public class WifiListenerService extends Service
+{
+
+ public static String NOTIFICATION_CHANNEL_ID = "org.pihole.dnsproxy.service.wifiListener.NOTIFICATION";
+ public static String ACTION_START = "org.pihole.dnsproxy.service.wifiListener.START";
+ public static String ACTION_STOP = "org.pihole.dnsproxy.service.wifiListener.STOP";
+ public static String ACTION_STOP_SET_PREFERENCE = "org.pihole.dnsproxy.service.wifiListener.STOP_SET_PREFERENCE";
+
+ private BroadcastReceiver receiver = new WifiListenerReceiver();
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ // start the service
+ if (intent.getAction().equals(WifiListenerService.ACTION_START)) {
+ this.listen();
+
+ return Service.START_STICKY;
+ }
+
+ // stop the service
+ else if (intent.getAction().equals(WifiListenerService.ACTION_STOP)) {
+ try {
+ this.deafen();
+ } catch (Exception exception) {}
+
+ return Service.START_NOT_STICKY;
+ }
+
+ // stop and disable
+ else if (intent.getAction().equals(WifiListenerService.ACTION_STOP_SET_PREFERENCE)) {
+ WifiListenerService.disable(this);
+
+ return Service.START_NOT_STICKY;
+ }
+
+ return Service.START_NOT_STICKY;
+ }
+
+ @Override
+ public void onDestroy() {
+ this.deafen();
+
+ super.onDestroy();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) { return null; }
+
+ /**
+ * Start the service
+ */
+ public static void start(Context context) {
+ context.startService((new Intent(context, WifiListenerService.class)).setAction(WifiListenerService.ACTION_START));
+ }
+
+ /**
+ * Stop the service
+ */
+ public static void stop(Context context) {
+ context.startService((new Intent(context, WifiListenerService.class)).setAction(WifiListenerService.ACTION_STOP));
+ }
+
+ /**
+ * Start/Stop based on setting
+ */
+ public static void toggle(Context context) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+
+ if (sharedPreferences.getBoolean("use_wifi_listener", false)) {
+ WifiListenerService.start(context);
+ } else {
+ WifiListenerService.stop(context);
+ }
+ }
+
+ /**
+ * Stop Wifi Listener and disable completely
+ */
+ public static void disable(Context context) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit();
+
+ WifiListenerService.stop(context);
+ sharedPreferencesEditor.putBoolean("use_wifi_listener", false);
+ sharedPreferencesEditor.commit();
+
+ WifiListenerService.OnActivationListener.disable(context);
+ }
+
+ /**
+ * Get current Wifi SSID
+ */
+ public static String getWifiSSID(Context context) {
+ WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ WifiInfo wifiInfo = wifiManager.getConnectionInfo();
+ String ssid = wifiInfo.getSSID();
+
+ // remove quotes around ssid
+ ssid = ssid.substring(1, ssid.length() - 1);
+
+ return ssid;
+ }
+
+ /**
+ * Setup listener
+ */
+ private void listen() {
+ registerReceiver(this.receiver, new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION));
+
+ this.startForeground();
+ }
+
+ /**
+ * Stop listening
+ */
+ private void deafen() {
+ unregisterReceiver(this.receiver);
+
+ stopForeground(true);
+ }
+
+ /**
+ * Start the Foreground notification process
+ */
+ private void startForeground() {
+ NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+ NotificationChannel channel = new NotificationChannel(
+ WifiListenerService.NOTIFICATION_CHANNEL_ID,
+ WifiListenerService.NOTIFICATION_CHANNEL_ID,
+ NotificationManager.IMPORTANCE_DEFAULT
+ );
+ manager.createNotificationChannel(channel);
+
+ Notification notification = new Notification.Builder(this, WifiListenerService.NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(R.drawable.logo)
+ .setContentTitle(getString(R.string.app_label) + " - WiFi Listener")
+ .setContentText(getString(R.string.wifi_listener_service__notification__text))
+ .setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, SettingsActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK))
+ .addAction(
+ R.drawable.logo,
+ getString(R.string.wifi_listener_service__notification__action__stop_listener),
+ PendingIntent.getService(this, 0,
+ (new Intent(this, WifiListenerService.class)).setAction(WifiListenerService.ACTION_STOP_SET_PREFERENCE),
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ )
+ .addAction(
+ R.drawable.logo,
+ getString(R.string.wifi_listener_service__notification__action__start_proxy),
+ PendingIntent.getService(this, 0,
+ (new Intent(this, DNSProxyService.class)).setAction(DNSProxyService.ACTION_START),
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ )
+ .build();
+
+ startForeground(2, notification);
+ }
+
+ /**
+ * SubClass to enable auto-activation
+ */
+ public static class OnActivationListener {
+
+ /**
+ * Disable auto-activation
+ */
+ public static void disable(Context context) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit();
+ LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+
+ sharedPreferencesEditor.putBoolean("use_wifi_listener_for_activation", false);
+ sharedPreferencesEditor.commit();
+
+ if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
+ context.startActivity((new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ }
+ }
+
+ /**
+ * Check if location services are needed
+ */
+ public static boolean checkLocationNeeded(Context context) {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+
+ if (!sharedPreferences.getBoolean("use_wifi_listener_for_activation", false)) {
+ return false;
+ }
+
+ LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+
+ return !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
+ }
+
+ /**
+ * Ask User to enable location services if they are needed
+ */
+ public static void askLocationIfNeeded(Activity context) {
+ if (checkLocationNeeded(context)) {
+ context.requestPermissions(new String[]{
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ }, 3765);
+
+ context.startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
+ }
+ }
+ }
+}