diff options
Diffstat (limited to 'mobile-kt/app')
-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 |
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 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)); + } + } + } +} |