android: Add settings activity and default profile selection
authorTobias Brunner <tobias@strongswan.org>
Fri, 8 Jun 2018 09:57:38 +0000 (11:57 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 3 Jul 2018 09:31:34 +0000 (11:31 +0200)
The default profile can then be used for a Quick Settings tile or the
Always-on VPN feature.

18 files changed:
src/frontends/android/app/build.gradle
src/frontends/android/app/src/main/AndroidManifest.xml
src/frontends/android/app/src/main/java/org/strongswan/android/data/VpnProfileDataSource.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/MainActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/SettingsActivity.java [new file with mode: 0644]
src/frontends/android/app/src/main/java/org/strongswan/android/ui/SettingsFragment.java [new file with mode: 0644]
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileControlActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/utils/Constants.java
src/frontends/android/app/src/main/res/menu/main.xml
src/frontends/android/app/src/main/res/values-de/strings.xml
src/frontends/android/app/src/main/res/values-pl/strings.xml
src/frontends/android/app/src/main/res/values-ru/strings.xml
src/frontends/android/app/src/main/res/values-ua/strings.xml
src/frontends/android/app/src/main/res/values-zh-rCN/strings.xml
src/frontends/android/app/src/main/res/values-zh-rTW/strings.xml
src/frontends/android/app/src/main/res/values/strings.xml
src/frontends/android/app/src/main/res/values/styles.xml
src/frontends/android/app/src/main/res/xml/settings.xml [new file with mode: 0644]

index 4184596..737787b 100644 (file)
@@ -45,6 +45,7 @@ android {
 dependencies {
     implementation 'com.android.support:appcompat-v7:26.0.2'
     implementation 'com.android.support:design:26.0.2'
+    implementation 'com.android.support:preference-v7:26.0.2'
     implementation 'com.android.support:support-v4:26.0.2'
     testImplementation 'junit:junit:4.12'
 }
index fc0fb4f..5d827a3 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-    Copyright (C) 2012-2015 Tobias Brunner
+    Copyright (C) 2012-2018 Tobias Brunner
     Copyright (C) 2012 Giuliano Grassi
     Copyright (C) 2012 Ralf Sager
     HSR Hochschule fuer Technik Rapperswil
             android:name=".ui.LogActivity"
             android:label="@string/log_title" >
         </activity>
+               <activity
+            android:name=".ui.SettingsActivity"
+            android:label="@string/pref_title">
+        </activity>
         <activity
             android:name=".ui.RemediationInstructionsActivity"
             android:label="@string/remediation_instructions_title" >
index b916170..afd0d4f 100644 (file)
@@ -382,6 +382,28 @@ public class VpnProfileDataSource
        }
 
        /**
+        * Get a single VPN profile from the database by its UUID as String.
+        * @param uuid the UUID of the VPN profile as String
+        * @return the profile or null, if not found
+        */
+       public VpnProfile getVpnProfile(String uuid)
+       {
+               try
+               {
+                       if (uuid != null)
+                       {
+                               return getVpnProfile(UUID.fromString(uuid));
+                       }
+                       return null;
+               }
+               catch (IllegalArgumentException e)
+               {
+                       e.printStackTrace();
+                       return null;
+               }
+       }
+
+       /**
         * Get a list of all VPN profiles stored in the database.
         * @return list of VPN profiles
         */
index 5971e1a..bfef8e9 100644 (file)
@@ -108,6 +108,10 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec
                                Intent logIntent = new Intent(this, LogActivity.class);
                                startActivity(logIntent);
                                return true;
+                       case R.id.menu_settings:
+                               Intent settingsIntent = new Intent(this, SettingsActivity.class);
+                               startActivity(settingsIntent);
+                               return true;
                        default:
                                return super.onOptionsItemSelected(item);
                }
diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SettingsActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SettingsActivity.java
new file mode 100644 (file)
index 0000000..ad28529
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+package org.strongswan.android.ui;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.MenuItem;
+
+public class SettingsActivity extends AppCompatActivity
+{
+
+       @Override
+       protected void onCreate(Bundle savedInstanceState)
+       {
+               super.onCreate(savedInstanceState);
+
+               getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+
+               getSupportFragmentManager().beginTransaction()
+                                                       .replace(android.R.id.content, new SettingsFragment())
+                                                       .commit();
+       }
+
+       @Override
+       public boolean onOptionsItemSelected(MenuItem item)
+       {
+               switch (item.getItemId())
+               {
+                       case android.R.id.home:
+                               finish();
+                               return true;
+                       default:
+                               return super.onOptionsItemSelected(item);
+               }
+       }
+}
diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SettingsFragment.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/SettingsFragment.java
new file mode 100644 (file)
index 0000000..b710c82
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+package org.strongswan.android.ui;
+
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceFragmentCompat;
+import android.support.v7.preference.PreferenceManager;
+
+import org.strongswan.android.R;
+import org.strongswan.android.data.VpnProfile;
+import org.strongswan.android.data.VpnProfileDataSource;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import static org.strongswan.android.utils.Constants.PREF_DEFAULT_VPN_PROFILE;
+import static org.strongswan.android.utils.Constants.PREF_DEFAULT_VPN_PROFILE_MRU;
+
+public class SettingsFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceChangeListener
+{
+       private ListPreference mDefaultVPNProfile;
+
+       @Override
+       public void onCreatePreferences(Bundle bundle, String s)
+       {
+               setPreferencesFromResource(R.xml.settings, s);
+
+               mDefaultVPNProfile = (ListPreference)findPreference(PREF_DEFAULT_VPN_PROFILE);
+               mDefaultVPNProfile.setOnPreferenceChangeListener(this);
+               if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
+               {
+                       mDefaultVPNProfile.setEnabled(false);
+               }
+       }
+
+       @Override
+       public void onResume()
+       {
+               super.onResume();
+
+               VpnProfileDataSource profiles = new VpnProfileDataSource(getActivity());
+               profiles.open();
+
+               List<VpnProfile> all = profiles.getAllVpnProfiles();
+               Collections.sort(all, new Comparator<VpnProfile>() {
+                       @Override
+                       public int compare(VpnProfile lhs, VpnProfile rhs)
+                       {
+                               return lhs.getName().compareToIgnoreCase(rhs.getName());
+                       }
+               });
+
+               ArrayList<CharSequence> entries = new ArrayList<>();
+               ArrayList<CharSequence> entryvalues = new ArrayList<>();
+
+               entries.add(getString(R.string.pref_default_vpn_profile_mru));
+               entryvalues.add(PREF_DEFAULT_VPN_PROFILE_MRU);
+
+               for (VpnProfile profile : all)
+               {
+                       entries.add(profile.getName());
+                       entryvalues.add(profile.getUUID().toString());
+               }
+               profiles.close();
+
+               if (entries.size() <= 1)
+               {
+                       mDefaultVPNProfile.setEnabled(false);
+               }
+               else
+               {
+                       mDefaultVPNProfile.setEnabled(true);
+                       mDefaultVPNProfile.setEntries(entries.toArray(new CharSequence[0]));
+                       mDefaultVPNProfile.setEntryValues(entryvalues.toArray(new CharSequence[0]));
+               }
+
+               SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getActivity());
+               setCurrentProfileName(pref.getString(PREF_DEFAULT_VPN_PROFILE, PREF_DEFAULT_VPN_PROFILE_MRU));
+       }
+
+       @Override
+       public boolean onPreferenceChange(Preference preference, Object newValue)
+       {
+               if (preference == mDefaultVPNProfile)
+               {
+                       setCurrentProfileName((String)newValue);
+               }
+               return true;
+       }
+
+       private void setCurrentProfileName(String uuid)
+       {
+               VpnProfileDataSource profiles = new VpnProfileDataSource(getActivity());
+               profiles.open();
+
+               if (!uuid.equals(PREF_DEFAULT_VPN_PROFILE_MRU))
+               {
+                       VpnProfile current = profiles.getVpnProfile(uuid);
+                       if (current != null)
+                       {
+                               mDefaultVPNProfile.setSummary(current.getName());
+                       }
+                       else
+                       {
+                               mDefaultVPNProfile.setSummary(R.string.profile_not_found);
+                       }
+               }
+               else
+               {
+                       mDefaultVPNProfile.setSummary(R.string.pref_default_vpn_profile_mru);
+               }
+               profiles.close();
+       }
+}
index b8e7447..9bc0cf0 100644 (file)
@@ -44,8 +44,6 @@ import org.strongswan.android.logic.CharonVpnService;
 import org.strongswan.android.logic.VpnStateService;
 import org.strongswan.android.logic.VpnStateService.State;
 
-import java.util.UUID;
-
 public class VpnProfileControlActivity extends AppCompatActivity
 {
        public static final String START_PROFILE = "org.strongswan.android.action.START_PROFILE";
@@ -254,14 +252,7 @@ public class VpnProfileControlActivity extends AppCompatActivity
                String profileUUID = intent.getStringExtra(EXTRA_VPN_PROFILE_ID);
                if (profileUUID != null)
                {
-                       try
-                       {
-                               profile = dataSource.getVpnProfile(UUID.fromString(profileUUID));
-                       }
-                       catch (Exception e)
-                       {       /* invalid UUID */
-                               e.printStackTrace();
-                       }
+                       profile = dataSource.getVpnProfile(profileUUID);
                }
                else
                {
index 16fdcda..2e5de7f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Tobias Brunner
+ * Copyright (C) 2016-2018 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -43,4 +43,14 @@ public final class Constants
         */
        public static final int NAT_KEEPALIVE_MAX = 120;
        public static final int NAT_KEEPALIVE_MIN = 10;
+
+       /**
+        * Preference key for default VPN profile
+        */
+       public static final String PREF_DEFAULT_VPN_PROFILE = "pref_default_vpn_profile";
+
+       /**
+        * Value used to signify that the most recently used profile should be used as default
+        */
+       public static final String PREF_DEFAULT_VPN_PROFILE_MRU = "pref_default_vpn_profile_mru";
 }
index 48a541b..7cb0917 100644 (file)
@@ -36,4 +36,9 @@
         android:title="@string/show_log"
         app:showAsAction="withText" />
 
+    <item
+        android:id="@+id/menu_settings"
+        android:title="@string/pref_title"
+        app:showAsAction="withText" />
+
 </menu>
index 975686e..97df885 100644 (file)
     <string name="permanent_notification_name">VPN Verbindungsstatus</string>
     <string name="permanent_notification_description">Zeigt Informationen zum Verbindungsstatus der VPN Verbindung und dient als permanente Notification dazu, den VPN Dienst im Hintergrund am Laufen zu halten.</string>
 
+    <!-- Settings -->
+    <string name="pref_title">Einstellungen</string>
+    <string name="pref_default_vpn_profile">Voreingestelltes VPN Profil</string>
+    <string name="pref_default_vpn_profile_mru">Verbinden mit zuletzt verwendetem Profil</string>
+
     <!-- Log view -->
     <string name="log_title">Log</string>
     <string name="send_log">Logdatei senden</string>
@@ -76,8 +81,8 @@
     <string name="profile_advanced_label">Erweiterte Einstellungen</string>
     <string name="profile_show_advanced_label">Erweiterte Einstellungen anzeigen</string>
     <string name="profile_remote_id_label">Server-Identität</string>
-    <string name="profile_remote_id_hint">Standardwert ist der konfigurierte Server. Eigene Werte werden explizit and den Server gesendet und während der Authentifizierung erzwungen</string>
-    <string name="profile_remote_id_hint_gateway">Standardwert ist \"%1$s\". Eigene Werte werden explizit and den Server gesendet und während der Authentifizierung erzwungen</string>
+    <string name="profile_remote_id_hint">Standardwert ist der konfigurierte Server. Eigene Werte werden explizit an den Server gesendet und während der Authentifizierung erzwungen</string>
+    <string name="profile_remote_id_hint_gateway">Standardwert ist \"%1$s\". Eigene Werte werden explizit an den Server gesendet und während der Authentifizierung erzwungen</string>
     <string name="profile_mtu_label">MTU des VPN Tunnel-Device</string>
     <string name="profile_mtu_hint">Falls der Standardwert in einem bestimmten Netzwerk nicht geeignet ist</string>
     <string name="profile_port_label">Server Port</string>
     <string name="profile_proposals_ike_hint">Für non-AEAD/klassische Verschlüsselungsalgorithmen wird ein Integritätsalgorithmus, eine pseudozufällige Funktion (PRF, optional, ansonsten wird eine auf dem Integritätsalgorithmus basierende verwendet) und eine Diffie-Hellman Gruppe benötigt (z.B. aes256-sha256-ecp256). Für kombinierte/AEAD Algorithmen wird der Integritätsalgorithmus weggelassen aber eine PRF wird benötigt (z.B. aes256gcm16-prfsha256-ecp256).</string>
     <string name="profile_proposals_esp_label">IPsec/ESP Algorithmen</string>
     <string name="profile_proposals_esp_hint">Für non-AEAD/klassische Verschlüsselungsalgorithmen wird ein Integritätsalgorithmus benötigt, eine Diffie-Hellman Gruppe ist optional (z.B. aes256-sha256 oder aes256-sha256-ecp256). Für kombinierte/AEAD Algorithmen wird der Integritätsalgorithmus weggelassen (z.B. aes256gcm16 oder aes256gcm16-ecp256). Falls eine DH Gruppe angegeben wird, kommt während dem IPsec SA Rekeying ein DH Schlüsselaustausch zur Anwendung. Beim initialen Verbindungsaufbau hat eine DH Gruppe hier keinen Einfluss, weil die Schlüssel dort von der IKE SA abgeleitet werden. Deshalb wird eine Fehlkonfiguration mit dem Server erst später während dem Rekeying zu einem Fehler führen.</string>
-    <string name="profile_import">VPN Profile importieren</string>
+    <string name="profile_import">VPN Profil importieren</string>
     <string name="profile_import_failed">VPN Profil-Import fehlgeschlagen</string>
     <string name="profile_import_failed_detail">VPN Profil-Import fehlgeschlagen: %1$s</string>
     <string name="profile_import_failed_not_found">Datei nicht gefunden</string>
index 835efd5..e9c52f1 100644 (file)
     <string name="permanent_notification_name">VPN connection state</string>
     <string name="permanent_notification_description">Provides information about the VPN connection state and serves as permanent notification to keep the VPN service running in the background.</string>
 
+    <!-- Settings -->
+    <string name="pref_title">Settings</string>
+    <string name="pref_default_vpn_profile">Default VPN profile</string>
+    <string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
+
     <!-- Log view -->
     <string name="log_title">Log</string>
     <string name="send_log">Prześlij log</string>
index 53e8375..5f16eec 100644 (file)
     <string name="permanent_notification_name">VPN connection state</string>
     <string name="permanent_notification_description">Provides information about the VPN connection state and serves as permanent notification to keep the VPN service running in the background.</string>
 
+    <!-- Settings -->
+    <string name="pref_title">Settings</string>
+    <string name="pref_default_vpn_profile">Default VPN profile</string>
+    <string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
+
     <!-- Log view -->
     <string name="log_title">Журнал</string>
     <string name="send_log">Отправить журнал</string>
index 8e41daf..53bcf71 100644 (file)
     <string name="permanent_notification_name">VPN connection state</string>
     <string name="permanent_notification_description">Provides information about the VPN connection state and serves as permanent notification to keep the VPN service running in the background.</string>
 
+    <!-- Settings -->
+    <string name="pref_title">Settings</string>
+    <string name="pref_default_vpn_profile">Default VPN profile</string>
+    <string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
+
     <!-- Log view -->
     <string name="log_title">Журнал</string>
     <string name="send_log">Відправити файл журналу</string>
index 0cb6bd0..72098cc 100644 (file)
     <string name="permanent_notification_name">VPN connection state</string>
     <string name="permanent_notification_description">Provides information about the VPN connection state and serves as permanent notification to keep the VPN service running in the background.</string>
 
+    <!-- Settings -->
+    <string name="pref_title">Settings</string>
+    <string name="pref_default_vpn_profile">Default VPN profile</string>
+    <string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
+
     <!-- Log view -->
     <string name="log_title">日志</string>
     <string name="send_log">发送日志文件</string>
index 168fdd7..ba9fdd0 100644 (file)
     <string name="permanent_notification_name">VPN connection state</string>
     <string name="permanent_notification_description">Provides information about the VPN connection state and serves as permanent notification to keep the VPN service running in the background.</string>
 
+    <!-- Settings -->
+    <string name="pref_title">Settings</string>
+    <string name="pref_default_vpn_profile">Default VPN profile</string>
+    <string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
+
     <!-- Log view -->
     <string name="log_title">日誌</string>
     <string name="send_log">發送日誌檔</string>
index 13d7187..cb507be 100644 (file)
     <string name="permanent_notification_name">VPN connection state</string>
     <string name="permanent_notification_description">Provides information about the VPN connection state and serves as permanent notification to keep the VPN service running in the background.</string>
 
+    <!-- Settings -->
+    <string name="pref_title">Settings</string>
+    <string name="pref_default_vpn_profile">Default VPN profile</string>
+    <string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
+
     <!-- Log view -->
     <string name="log_title">Log</string>
     <string name="send_log">Send log file</string>
index 83f34b6..4b7cc4c 100644 (file)
@@ -20,6 +20,7 @@
         <item name="colorPrimary">@color/primary</item>
         <item name="colorPrimaryDark">@color/primary_dark</item>
         <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
+        <item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
     </style>
 
     <style name="AlertDialogTheme.Base" parent="Theme.AppCompat.Dialog.Alert">
diff --git a/src/frontends/android/app/src/main/res/xml/settings.xml b/src/frontends/android/app/src/main/res/xml/settings.xml
new file mode 100644 (file)
index 0000000..908a888
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2018 Tobias Brunner
+    HSR Hochschule fuer Technik Rapperswil
+
+    This program is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+
+    This program is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+-->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <ListPreference
+        android:key="pref_default_vpn_profile"
+        android:title="@string/pref_default_vpn_profile"
+        android:summary="@string/pref_default_vpn_profile_mru" />
+
+</PreferenceScreen>