Merge branch 'android-tabs'
authorTobias Brunner <tobias@strongswan.org>
Wed, 27 Apr 2016 12:35:47 +0000 (14:35 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 27 Apr 2016 12:38:08 +0000 (14:38 +0200)
This migrates some deprecated Android APIs to replacements provided by
the support library.  This also changes the theme slightly.

36 files changed:
src/frontends/android/.gitignore
src/frontends/android/app/build.gradle
src/frontends/android/app/src/main/AndroidManifest.xml
src/frontends/android/app/src/main/java/org/strongswan/android/logic/TrustedCertificateManager.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/CertificateDeleteConfirmationDialog.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/ImcStateFragment.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/LogActivity.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/RemediationInstructionsActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificateImportActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificateListFragment.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificatesActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileSelectActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnStateFragment.java
src/frontends/android/app/src/main/res/drawable/activated_background.xml [new file with mode: 0644]
src/frontends/android/app/src/main/res/layout/log_fragment.xml
src/frontends/android/app/src/main/res/layout/trusted_certificates_activity.xml
src/frontends/android/app/src/main/res/menu/certificates.xml
src/frontends/android/app/src/main/res/menu/log.xml
src/frontends/android/app/src/main/res/menu/main.xml
src/frontends/android/app/src/main/res/menu/profile_edit.xml
src/frontends/android/app/src/main/res/menu/profile_list.xml
src/frontends/android/app/src/main/res/menu/profile_list_context.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-v15/styles.xml [new file with mode: 0644]
src/frontends/android/app/src/main/res/values-v21/styles.xml [new file with mode: 0644]
src/frontends/android/app/src/main/res/values/colors.xml
src/frontends/android/app/src/main/res/values/strings.xml
src/frontends/android/app/src/main/res/values/styles.xml
src/frontends/android/build.gradle
src/frontends/android/gradle/wrapper/gradle-wrapper.properties

index 7e4bcfd..aeb7cd7 100644 (file)
@@ -1,5 +1,6 @@
 .gradle/
 .idea/
+build/
 app/build/
 app/src/main/libs
 app/src/main/obj
index 46927ea..9ef7d17 100644 (file)
@@ -1,8 +1,8 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 21
-    buildToolsVersion "22.0.1"
+    compileSdkVersion 23
+    buildToolsVersion "23.0.3"
 
     defaultConfig {
         applicationId "org.strongswan.android"
@@ -29,6 +29,7 @@ android {
 
     tasks.withType(JavaCompile) {
         compileTask -> compileTask.dependsOn buildNative
+        options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
     }
 
     clean.dependsOn 'cleanNative'
@@ -42,5 +43,7 @@ android {
 }
 
 dependencies {
+    compile 'com.android.support:appcompat-v7:23.3.0'
+    compile 'com.android.support:design:23.3.0'
     testCompile 'junit:junit:4.12'
 }
index 2ab833c..da465ba 100644 (file)
@@ -66,7 +66,7 @@
         <activity
             android:name=".ui.TrustedCertificateImportActivity"
             android:label="@string/import_certificate"
-            android:theme="@android:style/Theme.Holo.Dialog.NoActionBar" >
+            android:theme="@style/AlertDialogTheme" >
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
                 <category android:name="android.intent.category.DEFAULT" />
index 82a7cbe..843dfaf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
  * Copyright (C) 2012 Giuliano Grassi
  * Copyright (C) 2012 Ralf Sager
  * Hochschule fuer Technik Rapperswil
@@ -17,6 +17,8 @@
 
 package org.strongswan.android.logic;
 
+import android.util.Log;
+
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.cert.Certificate;
@@ -24,11 +26,10 @@ import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.Hashtable;
+import java.util.Observable;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import android.util.Log;
-
-public class TrustedCertificateManager
+public class TrustedCertificateManager extends Observable
 {
        private static final String TAG = TrustedCertificateManager.class.getSimpleName();
        private final ReentrantReadWriteLock mLock = new ReentrantReadWriteLock();
@@ -61,13 +62,13 @@ public class TrustedCertificateManager
         */
        private TrustedCertificateManager()
        {
-               for (String name : new String[] { "LocalCertificateStore", "AndroidCAStore" })
+               for (String name : new String[]{"LocalCertificateStore", "AndroidCAStore"})
                {
                        KeyStore store;
                        try
                        {
                                store = KeyStore.getInstance(name);
-                               store.load(null,null);
+                               store.load(null, null);
                                mKeyStores.add(store);
                        }
                        catch (Exception e)
@@ -81,12 +82,14 @@ public class TrustedCertificateManager
        /**
         * This is not instantiated until the first call to getInstance()
         */
-       private static class Singleton {
+       private static class Singleton
+       {
                public static final TrustedCertificateManager mInstance = new TrustedCertificateManager();
        }
 
        /**
         * Get the single instance of the CA certificate manager.
+        *
         * @return CA certificate manager
         */
        public static TrustedCertificateManager getInstance()
@@ -97,12 +100,17 @@ public class TrustedCertificateManager
        /**
         * Invalidates the current load state so that the next call to load()
         * will force a reload of the cached CA certificates.
+        *
+        * Observers are notified when this method is called.
+        *
         * @return reference to itself
         */
        public TrustedCertificateManager reset()
        {
                Log.d(TAG, "Force reload of cached CA certificates on next load");
                this.mReload = true;
+               this.setChanged();
+               this.notifyObservers();
                return this;
        }
 
@@ -110,6 +118,9 @@ public class TrustedCertificateManager
         * Ensures that the certificates are loaded but does not force a reload.
         * As this takes a while if the certificates are not loaded yet it should
         * be called asynchronously.
+        *
+        * Observers are only notified when the certificates are initially loaded, not when reloaded.
+        *
         * @return reference to itself
         */
        public TrustedCertificateManager load()
@@ -138,12 +149,18 @@ public class TrustedCertificateManager
                        fetchCertificates(certs, store);
                }
                this.mCACerts = certs;
-               this.mLoaded = true;
+               if (!this.mLoaded)
+               {
+                       this.setChanged();
+                       this.notifyObservers();
+                       this.mLoaded = true;
+               }
                Log.d(TAG, "Cached CA certificates loaded");
        }
 
        /**
         * Load all X.509 certificates from the given KeyStore.
+        *
         * @param certs Hashtable to store certificates in
         * @param store KeyStore to load certificates from
         */
@@ -171,6 +188,7 @@ public class TrustedCertificateManager
 
        /**
         * Retrieve the CA certificate with the given alias.
+        *
         * @param alias alias of the certificate to get
         * @return the certificate, null if not found
         */
@@ -208,6 +226,7 @@ public class TrustedCertificateManager
 
        /**
         * Get all CA certificates (from all keystores).
+        *
         * @return Hashtable mapping aliases to certificates
         */
        @SuppressWarnings("unchecked")
@@ -222,6 +241,7 @@ public class TrustedCertificateManager
 
        /**
         * Get all certificates from the given source.
+        *
         * @param source type to filter certificates
         * @return Hashtable mapping aliases to certificates
         */
index c381900..e8d12fd 100644 (file)
 
 package org.strongswan.android.ui;
 
-import org.strongswan.android.R;
-
 import android.app.Activity;
-import android.app.AlertDialog;
 import android.app.Dialog;
-import android.app.DialogFragment;
 import android.content.DialogInterface;
 import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatDialogFragment;
+
+import org.strongswan.android.R;
 
 /**
  * Class that displays a confirmation dialog to delete a selected local
  * certificate.
  */
-public class CertificateDeleteConfirmationDialog extends DialogFragment
+public class CertificateDeleteConfirmationDialog extends AppCompatDialogFragment
 {
        public static final String ALIAS = "alias";
        OnCertificateDeleteListener mListener;
index 5b17997..7328693 100644 (file)
 
 package org.strongswan.android.ui;
 
-import java.util.ArrayList;
-
-import org.strongswan.android.R;
-import org.strongswan.android.logic.VpnStateService;
-import org.strongswan.android.logic.VpnStateService.VpnStateListener;
-import org.strongswan.android.logic.imc.ImcState;
-import org.strongswan.android.logic.imc.RemediationInstruction;
-
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
@@ -33,6 +25,7 @@ import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.support.v4.content.ContextCompat;
 import android.view.GestureDetector;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -44,13 +37,24 @@ import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import org.strongswan.android.R;
+import org.strongswan.android.logic.VpnStateService;
+import org.strongswan.android.logic.VpnStateService.VpnStateListener;
+import org.strongswan.android.logic.imc.ImcState;
+import org.strongswan.android.logic.imc.RemediationInstruction;
+
+import java.util.ArrayList;
+
 public class ImcStateFragment extends Fragment implements VpnStateListener
 {
+       private int mColorIsolate;
+       private int mColorBlock;
        private TextView mStateView;
        private TextView mAction;
        private LinearLayout mButton;
        private VpnStateService mService;
-       private final ServiceConnection mServiceConnection = new ServiceConnection() {
+       private final ServiceConnection mServiceConnection = new ServiceConnection()
+       {
                @Override
                public void onServiceDisconnected(ComponentName name)
                {
@@ -71,6 +75,9 @@ public class ImcStateFragment extends Fragment implements VpnStateListener
        {
                super.onCreate(savedInstanceState);
 
+               mColorIsolate = ContextCompat.getColor(getActivity(), R.color.warning_text);
+               mColorBlock = ContextCompat.getColor(getActivity(), R.color.error_text);
+
                /* bind to the service only seems to work from the ApplicationContext */
                Context context = getActivity().getApplicationContext();
                context.bindService(new Intent(context, VpnStateService.class),
@@ -86,7 +93,8 @@ public class ImcStateFragment extends Fragment implements VpnStateListener
                View view = inflater.inflate(R.layout.imc_state_fragment, container, false);
 
                mButton = (LinearLayout)view.findViewById(R.id.imc_state_button);
-               mButton.setOnClickListener(new OnClickListener() {
+               mButton.setOnClickListener(new OnClickListener()
+               {
                        @Override
                        public void onClick(View v)
                        {
@@ -104,7 +112,8 @@ public class ImcStateFragment extends Fragment implements VpnStateListener
                                startActivity(intent);
                        }
                });
-               final GestureDetector gestures = new GestureDetector(getActivity(), new GestureDetector.SimpleOnGestureListener() {
+               final GestureDetector gestures = new GestureDetector(getActivity(), new GestureDetector.SimpleOnGestureListener()
+               {
                        /* a better value would be getScaledTouchExplorationTapSlop() but that is hidden */
                        private final int mMinDistance = ViewConfiguration.get(getActivity()).getScaledTouchSlop() * 4;
 
@@ -122,7 +131,8 @@ public class ImcStateFragment extends Fragment implements VpnStateListener
                                return false;
                        }
                });
-               mButton.setOnTouchListener(new OnTouchListener() {
+               mButton.setOnTouchListener(new OnTouchListener()
+               {
                        @Override
                        public boolean onTouch(View v, MotionEvent event)
                        {
@@ -190,12 +200,12 @@ public class ImcStateFragment extends Fragment implements VpnStateListener
                                break;
                        case ISOLATE:
                                mStateView.setText(R.string.imc_state_isolate);
-                               mStateView.setTextColor(getResources().getColor(R.color.warning_text));
+                               mStateView.setTextColor(mColorIsolate);
                                ft.show(this);
                                break;
                        case BLOCK:
                                mStateView.setText(R.string.imc_state_block);
-                               mStateView.setTextColor(getResources().getColor(R.color.error_text));
+                               mStateView.setTextColor(mColorBlock);
                                ft.show(this);
                                break;
                }
index a5efecc..4ad2ebb 100644 (file)
 
 package org.strongswan.android.ui;
 
-import java.io.File;
-
-import org.strongswan.android.R;
-import org.strongswan.android.data.LogContentProvider;
-import org.strongswan.android.logic.CharonVpnService;
-
-import android.app.Activity;
 import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.widget.Toast;
 
-public class LogActivity extends Activity
+import org.strongswan.android.R;
+import org.strongswan.android.data.LogContentProvider;
+import org.strongswan.android.logic.CharonVpnService;
+
+import java.io.File;
+
+public class LogActivity extends AppCompatActivity
 {
        @Override
        public void onCreate(Bundle savedInstanceState)
@@ -37,7 +37,7 @@ public class LogActivity extends Activity
                super.onCreate(savedInstanceState);
                setContentView(R.layout.log_activity);
 
-               getActionBar().setDisplayHomeAsUpEnabled(true);
+               getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }
 
        @Override
@@ -74,7 +74,7 @@ public class LogActivity extends Activity
                                }
 
                                Intent intent = new Intent(Intent.ACTION_SEND);
-                               intent.putExtra(Intent.EXTRA_EMAIL, new String[] { MainActivity.CONTACT_EMAIL });
+                               intent.putExtra(Intent.EXTRA_EMAIL, new String[]{MainActivity.CONTACT_EMAIL});
                                intent.putExtra(Intent.EXTRA_SUBJECT, String.format(getString(R.string.log_mail_subject), version));
                                intent.setType("text/plain");
                                intent.putExtra(Intent.EXTRA_STREAM, LogContentProvider.createContentUri());
index e1b3e07..3d53240 100644 (file)
 
 package org.strongswan.android.ui;
 
-import org.strongswan.android.R;
-import org.strongswan.android.data.VpnProfile;
-import org.strongswan.android.data.VpnProfileDataSource;
-import org.strongswan.android.data.VpnType.VpnTypeFeature;
-import org.strongswan.android.logic.CharonVpnService;
-import org.strongswan.android.logic.TrustedCertificateManager;
-import org.strongswan.android.logic.VpnStateService;
-import org.strongswan.android.logic.VpnStateService.State;
-import org.strongswan.android.ui.VpnProfileListFragment.OnVpnProfileSelectedListener;
-
-import android.app.ActionBar;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.AlertDialog.Builder;
 import android.app.Dialog;
-import android.app.DialogFragment;
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
@@ -46,6 +31,10 @@ import android.net.VpnService;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.app.AppCompatDialogFragment;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -54,12 +43,24 @@ import android.view.Window;
 import android.widget.EditText;
 import android.widget.Toast;
 
-public class MainActivity extends Activity implements OnVpnProfileSelectedListener
+import org.strongswan.android.R;
+import org.strongswan.android.data.VpnProfile;
+import org.strongswan.android.data.VpnProfileDataSource;
+import org.strongswan.android.data.VpnType.VpnTypeFeature;
+import org.strongswan.android.logic.CharonVpnService;
+import org.strongswan.android.logic.TrustedCertificateManager;
+import org.strongswan.android.logic.VpnStateService;
+import org.strongswan.android.logic.VpnStateService.State;
+import org.strongswan.android.ui.VpnProfileListFragment.OnVpnProfileSelectedListener;
+
+public class MainActivity extends AppCompatActivity implements OnVpnProfileSelectedListener
 {
        public static final String CONTACT_EMAIL = "android@strongswan.org";
        public static final String START_PROFILE = "org.strongswan.android.action.START_PROFILE";
        public static final String EXTRA_VPN_PROFILE_ID = "org.strongswan.android.VPN_PROFILE_ID";
-       /** Use "bring your own device" (BYOD) features */
+       /**
+        * Use "bring your own device" (BYOD) features
+        */
        public static final boolean USE_BYOD = true;
        private static final int PREPARE_VPN_SERVICE = 0;
        private static final String PROFILE_NAME = "org.strongswan.android.MainActivity.PROFILE_NAME";
@@ -69,7 +70,8 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
 
        private Bundle mProfileInfo;
        private VpnStateService mService;
-       private final ServiceConnection mServiceConnection = new ServiceConnection() {
+       private final ServiceConnection mServiceConnection = new ServiceConnection()
+       {
                @Override
                public void onServiceDisconnected(ComponentName name)
                {
@@ -91,16 +93,18 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
-               super.onCreate(savedInstanceState);
                requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+               super.onCreate(savedInstanceState);
                setContentView(R.layout.main);
 
+               ActionBar bar = getSupportActionBar();
+               bar.setDisplayShowHomeEnabled(true);
+               bar.setDisplayShowTitleEnabled(false);
+               bar.setIcon(R.drawable.ic_launcher);
+
                this.bindService(new Intent(this, VpnStateService.class),
                                                 mServiceConnection, Service.BIND_AUTO_CREATE);
 
-               ActionBar bar = getActionBar();
-               bar.setDisplayShowTitleEnabled(false);
-
                /* load CA certificates in a background task */
                new LoadCertificatesTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        }
@@ -157,6 +161,7 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
        /**
         * Prepare the VpnService. If this succeeds the current VPN profile is
         * started.
+        *
         * @param profileInfo a bundle containing the information about the profile to be started
         */
        protected void prepareVpnService(Bundle profileInfo)
@@ -231,7 +236,7 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
 
                        ConfirmationDialog dialog = new ConfirmationDialog();
                        dialog.setArguments(profileInfo);
-                       dialog.show(this.getFragmentManager(), DIALOG_TAG);
+                       dialog.show(this.getSupportFragmentManager(), DIALOG_TAG);
                        return;
                }
                startVpnProfile(profileInfo);
@@ -239,6 +244,7 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
 
        /**
         * Start the given VPN profile asking the user for a password if required.
+        *
         * @param profileInfo data about the profile
         */
        private void startVpnProfile(Bundle profileInfo)
@@ -248,7 +254,7 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
                {
                        LoginDialog login = new LoginDialog();
                        login.setArguments(profileInfo);
-                       login.show(getFragmentManager(), DIALOG_TAG);
+                       login.show(getSupportFragmentManager(), DIALOG_TAG);
                        return;
                }
                prepareVpnService(profileInfo);
@@ -257,6 +263,7 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
        /**
         * Start the VPN profile referred to by the given intent. Displays an error
         * if the profile doesn't exist.
+        *
         * @param intent Intent that caused us to start this
         */
        private void startVpnProfile(Intent intent)
@@ -291,11 +298,13 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
                {
                        setProgressBarIndeterminateVisibility(true);
                }
+
                @Override
                protected TrustedCertificateManager doInBackground(Void... params)
                {
                        return TrustedCertificateManager.getInstance().load();
                }
+
                @Override
                protected void onPostExecute(TrustedCertificateManager result)
                {
@@ -322,7 +331,7 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
         * Class that displays a confirmation dialog if a VPN profile is already connected
         * and then initiates the selected VPN profile if the user confirms the dialog.
         */
-       public static class ConfirmationDialog extends DialogFragment
+       public static class ConfirmationDialog extends AppCompatDialogFragment
        {
                @Override
                public Dialog onCreateDialog(Bundle savedInstanceState)
@@ -345,7 +354,8 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
                                .setIcon(icon)
                                .setTitle(String.format(getString(title), profileInfo.getString(PROFILE_NAME)))
                                .setMessage(message)
-                               .setPositiveButton(button, new DialogInterface.OnClickListener() {
+                               .setPositiveButton(button, new DialogInterface.OnClickListener()
+                               {
                                        @Override
                                        public void onClick(DialogInterface dialog, int whichButton)
                                        {
@@ -353,7 +363,8 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
                                                activity.startVpnProfile(profileInfo);
                                        }
                                })
-                               .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+                               .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
+                               {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which)
                                        {
@@ -367,7 +378,7 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
         * Class that displays a login dialog and initiates the selected VPN
         * profile if the user confirms the dialog.
         */
-       public static class LoginDialog extends DialogFragment
+       public static class LoginDialog extends AppCompatDialogFragment
        {
                @Override
                public Dialog onCreateDialog(Bundle savedInstanceState)
@@ -379,10 +390,11 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
                        username.setText(profileInfo.getString(VpnProfileDataSource.KEY_USERNAME));
                        final EditText password = (EditText)view.findViewById(R.id.password);
 
-                       Builder adb = new AlertDialog.Builder(getActivity());
+                       AlertDialog.Builder adb = new AlertDialog.Builder(getActivity());
                        adb.setView(view);
                        adb.setTitle(getString(R.string.login_title));
-                       adb.setPositiveButton(R.string.login_confirm, new DialogInterface.OnClickListener() {
+                       adb.setPositiveButton(R.string.login_confirm, new DialogInterface.OnClickListener()
+                       {
                                @Override
                                public void onClick(DialogInterface dialog, int whichButton)
                                {
@@ -391,7 +403,8 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
                                        activity.prepareVpnService(profileInfo);
                                }
                        });
-                       adb.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+                       adb.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
+                       {
                                @Override
                                public void onClick(DialogInterface dialog, int which)
                                {
@@ -406,17 +419,17 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
         * Class representing an error message which is displayed if VpnService is
         * not supported on the current device.
         */
-       public static class VpnNotSupportedError extends DialogFragment
+       public static class VpnNotSupportedError extends AppCompatDialogFragment
        {
                static final String ERROR_MESSAGE_ID = "org.strongswan.android.VpnNotSupportedError.MessageId";
 
-               public static void showWithMessage(Activity activity, int messageId)
+               public static void showWithMessage(AppCompatActivity activity, int messageId)
                {
                        Bundle bundle = new Bundle();
                        bundle.putInt(ERROR_MESSAGE_ID, messageId);
                        VpnNotSupportedError dialog = new VpnNotSupportedError();
                        dialog.setArguments(bundle);
-                       dialog.show(activity.getFragmentManager(), DIALOG_TAG);
+                       dialog.show(activity.getSupportFragmentManager(), DIALOG_TAG);
                }
 
                @Override
@@ -428,7 +441,8 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
                                .setTitle(R.string.vpn_not_supported_title)
                                .setMessage(messageId)
                                .setCancelable(false)
-                               .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                               .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
+                               {
                                        @Override
                                        public void onClick(DialogInterface dialog, int id)
                                        {
index 66d0de2..7e7e870 100644 (file)
 
 package org.strongswan.android.ui;
 
-import java.util.ArrayList;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.MenuItem;
 
 import org.strongswan.android.R;
 import org.strongswan.android.logic.imc.RemediationInstruction;
 import org.strongswan.android.ui.RemediationInstructionsFragment.OnRemediationInstructionSelectedListener;
 
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.MenuItem;
+import java.util.ArrayList;
 
-public class RemediationInstructionsActivity extends Activity implements OnRemediationInstructionSelectedListener
+public class RemediationInstructionsActivity extends AppCompatActivity implements OnRemediationInstructionSelectedListener
 {
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.remediation_instructions);
-               getActionBar().setDisplayHomeAsUpEnabled(true);
+               getSupportActionBar().setDisplayHomeAsUpEnabled(true);
 
                if (savedInstanceState != null)
                {       /* only update if we're not restoring */
@@ -64,7 +64,7 @@ public class RemediationInstructionsActivity extends Activity implements OnRemed
                                {
                                        finish();
                                }
-                               getActionBar().setTitle(getTitle());
+                               getSupportActionBar().setTitle(getTitle());
                                return true;
                        default:
                                return super.onOptionsItemSelected(item);
@@ -88,7 +88,7 @@ public class RemediationInstructionsActivity extends Activity implements OnRemed
                        frag.setArguments(args);
 
                        getFragmentManager().beginTransaction().replace(R.id.fragment_container, frag).addToBackStack(null).commit();
-                       getActionBar().setTitle(instruction.getTitle());
+                       getSupportActionBar().setTitle(instruction.getTitle());
                }
        }
 }
index 61bd2c9..6b8eb2e 100644 (file)
 
 package org.strongswan.android.ui;
 
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.security.KeyStore;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-
-import org.strongswan.android.R;
-import org.strongswan.android.data.VpnProfileDataSource;
-import org.strongswan.android.logic.TrustedCertificateManager;
-
 import android.annotation.TargetApi;
 import android.app.Activity;
-import android.app.AlertDialog;
 import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.FragmentTransaction;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.app.AppCompatDialogFragment;
 import android.widget.Toast;
 
-public class TrustedCertificateImportActivity extends Activity
+import org.strongswan.android.R;
+import org.strongswan.android.data.VpnProfileDataSource;
+import org.strongswan.android.logic.TrustedCertificateManager;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+public class TrustedCertificateImportActivity extends AppCompatActivity
 {
        private static final int OPEN_DOCUMENT = 0;
        private static final String DIALOG_TAG = "Dialog";
 
        /* same as those listed in the manifest */
        private static final String[] ACCEPTED_MIME_TYPES = {
-                                                                                                                "application/x-x509-ca-cert",
-                                                                                                                "application/x-x509-server-cert",
-                                                                                                                "application/x-pem-file",
-                                                                                                                "application/pkix-cert"
+               "application/x-x509-ca-cert",
+               "application/x-x509-server-cert",
+               "application/x-pem-file",
+               "application/pkix-cert"
        };
 
        @TargetApi(Build.VERSION_CODES.KITKAT)
@@ -97,6 +98,7 @@ public class TrustedCertificateImportActivity extends Activity
 
        /**
         * Import the file pointed to by the given URI as a certificate.
+        *
         * @param uri
         */
        private void importCertificate(Uri uri)
@@ -117,13 +119,14 @@ public class TrustedCertificateImportActivity extends Activity
                Bundle args = new Bundle();
                args.putSerializable(VpnProfileDataSource.KEY_CERTIFICATE, certificate);
                dialog.setArguments(args);
-               FragmentTransaction ft = getFragmentManager().beginTransaction();
+               FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                ft.add(dialog, DIALOG_TAG);
                ft.commit();
        }
 
        /**
         * Load the file from the given URI and try to parse it as X.509 certificate.
+        *
         * @param uri
         * @return certificate or null
         */
@@ -151,6 +154,7 @@ public class TrustedCertificateImportActivity extends Activity
 
        /**
         * Try to store the given certificate in the KeyStore.
+        *
         * @param certificate
         * @return whether it was successfully stored
         */
@@ -175,7 +179,7 @@ public class TrustedCertificateImportActivity extends Activity
         * Class that displays a confirmation dialog when a certificate should get
         * imported. If the user confirms the import we try to store it.
         */
-       public static class ConfirmImportDialog extends DialogFragment
+       public static class ConfirmImportDialog extends AppCompatDialogFragment
        {
                @Override
                public Dialog onCreateDialog(Bundle savedInstanceState)
@@ -188,7 +192,8 @@ public class TrustedCertificateImportActivity extends Activity
                                .setIcon(R.drawable.ic_launcher)
                                .setTitle(R.string.import_certificate)
                                .setMessage(certificate.getSubjectDN().toString())
-                               .setPositiveButton(R.string.import_certificate, new DialogInterface.OnClickListener() {
+                               .setPositiveButton(R.string.import_certificate, new DialogInterface.OnClickListener()
+                               {
                                        @Override
                                        public void onClick(DialogInterface dialog, int whichButton)
                                        {
@@ -205,7 +210,8 @@ public class TrustedCertificateImportActivity extends Activity
                                                getActivity().finish();
                                        }
                                })
-                               .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+                               .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
+                               {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which)
                                        {
index 8bd39c4..9782a30 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
  * Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
 
 package org.strongswan.android.ui;
 
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map.Entry;
-
-import org.strongswan.android.R;
-import org.strongswan.android.logic.TrustedCertificateManager;
-import org.strongswan.android.logic.TrustedCertificateManager.TrustedCertificateSource;
-import org.strongswan.android.security.TrustedCertificateEntry;
-import org.strongswan.android.ui.adapter.TrustedCertificateAdapter;
-
-import android.app.Activity;
-import android.app.ListFragment;
-import android.app.LoaderManager.LoaderCallbacks;
-import android.content.AsyncTaskLoader;
 import android.content.Context;
-import android.content.Loader;
 import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.support.v4.app.LoaderManager.LoaderCallbacks;
+import android.support.v4.content.AsyncTaskLoader;
+import android.support.v4.content.Loader;
 import android.text.TextUtils;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -44,6 +30,21 @@ import android.widget.ListView;
 import android.widget.SearchView;
 import android.widget.SearchView.OnQueryTextListener;
 
+import org.strongswan.android.R;
+import org.strongswan.android.logic.TrustedCertificateManager;
+import org.strongswan.android.logic.TrustedCertificateManager.TrustedCertificateSource;
+import org.strongswan.android.security.TrustedCertificateEntry;
+import org.strongswan.android.ui.adapter.TrustedCertificateAdapter;
+
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Observable;
+import java.util.Observer;
+
 public class TrustedCertificateListFragment extends ListFragment implements LoaderCallbacks<List<TrustedCertificateEntry>>, OnQueryTextListener
 {
        public static final String EXTRA_CERTIFICATE_SOURCE = "certificate_source";
@@ -54,7 +55,8 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
        /**
         * The activity containing this fragment should implement this interface
         */
-       public interface OnTrustedCertificateSelectedListener {
+       public interface OnTrustedCertificateSelectedListener
+       {
                public void onTrustedCertificateSelected(TrustedCertificateEntry selected);
        }
 
@@ -87,13 +89,13 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
        }
 
        @Override
-       public void onAttach(Activity activity)
+       public void onAttach(Context context)
        {
-               super.onAttach(activity);
+               super.onAttach(context);
 
-               if (activity instanceof OnTrustedCertificateSelectedListener)
+               if (context instanceof OnTrustedCertificateSelectedListener)
                {
-                       mListener = (OnTrustedCertificateSelectedListener)activity;
+                       mListener = (OnTrustedCertificateSelectedListener)context;
                }
        }
 
@@ -123,18 +125,6 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
                return true;
        }
 
-       /**
-        * Reset the loader of this list fragment
-        */
-       public void reset()
-       {
-               if (isResumed())
-               {
-                       setListShown(false);
-               }
-               getLoaderManager().restartLoader(0, null, this);
-       }
-
        @Override
        public Loader<List<TrustedCertificateEntry>> onCreateLoader(int id, Bundle args)
        {       /* we don't need the id as we have only one loader */
@@ -175,6 +165,7 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
        {
                private List<TrustedCertificateEntry> mData;
                private final TrustedCertificateSource mSource;
+               private TrustedCertificateManagerObserver mObserver;
 
                public CertificateListLoader(Context context, TrustedCertificateSource source)
                {
@@ -186,7 +177,7 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
                public List<TrustedCertificateEntry> loadInBackground()
                {
                        TrustedCertificateManager certman = TrustedCertificateManager.getInstance().load();
-                       Hashtable<String,X509Certificate> certificates = certman.getCACertificates(mSource);
+                       Hashtable<String, X509Certificate> certificates = certman.getCACertificates(mSource);
                        List<TrustedCertificateEntry> selected;
 
                        selected = new ArrayList<TrustedCertificateEntry>();
@@ -204,9 +195,11 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
                        if (mData != null)
                        {       /* if we have data ready, deliver it directly */
                                deliverResult(mData);
-                               return;
                        }
-                       forceLoad();
+                       if (takeContentChanged() || mData == null)
+                       {
+                               forceLoad();
+                       }
                }
 
                @Override
@@ -220,6 +213,11 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
                        if (isStarted())
                        {       /* if it is started we deliver the data directly,
                                 * otherwise this is handled in onStartLoading */
+                               if (mObserver == null)
+                               {
+                                       mObserver = new TrustedCertificateManagerObserver();
+                                       TrustedCertificateManager.getInstance().addObserver(mObserver);
+                               }
                                super.deliverResult(data);
                        }
                }
@@ -227,7 +225,34 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
                @Override
                protected void onReset()
                {
+                       if (mObserver != null)
+                       {
+                               TrustedCertificateManager.getInstance().deleteObserver(mObserver);
+                               mObserver = null;
+                       }
                        mData = null;
+                       super.onReset();
+               }
+
+               @Override
+               protected void onAbandon()
+               {
+                       if (mObserver != null)
+                       {
+                               TrustedCertificateManager.getInstance().deleteObserver(mObserver);
+                               mObserver = null;
+                       }
+               }
+
+               private class TrustedCertificateManagerObserver implements Observer
+               {
+                       private ForceLoadContentObserver mContentObserver = new ForceLoadContentObserver();
+
+                       @Override
+                       public void update(Observable observable, Object data)
+                       {
+                               mContentObserver.onChange(false);
+                       }
                }
        }
 }
index 663950c..fd8a519 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
  * Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
 
 package org.strongswan.android.ui;
 
-import java.security.KeyStore;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.design.widget.TabLayout;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.view.Menu;
+import android.view.MenuItem;
 
 import org.strongswan.android.R;
 import org.strongswan.android.data.VpnProfileDataSource;
@@ -24,22 +37,15 @@ import org.strongswan.android.logic.TrustedCertificateManager.TrustedCertificate
 import org.strongswan.android.security.TrustedCertificateEntry;
 import org.strongswan.android.ui.CertificateDeleteConfirmationDialog.OnCertificateDeleteListener;
 
-import android.app.ActionBar;
-import android.app.ActionBar.Tab;
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentTransaction;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuItem;
+import java.security.KeyStore;
 
-public class TrustedCertificatesActivity extends Activity implements TrustedCertificateListFragment.OnTrustedCertificateSelectedListener, OnCertificateDeleteListener
+public class TrustedCertificatesActivity extends AppCompatActivity implements TrustedCertificateListFragment.OnTrustedCertificateSelectedListener, OnCertificateDeleteListener
 {
        public static final String SELECT_CERTIFICATE = "org.strongswan.android.action.SELECT_CERTIFICATE";
        private static final String DIALOG_TAG = "Dialog";
        private static final int IMPORT_CERTIFICATE = 0;
+       private TrustedCertificatesPagerAdapter mAdapter;
+       private ViewPager mPager;
        private boolean mSelect;
 
        @Override
@@ -48,42 +54,18 @@ public class TrustedCertificatesActivity extends Activity implements TrustedCert
                super.onCreate(savedInstanceState);
                setContentView(R.layout.trusted_certificates_activity);
 
-               ActionBar actionBar = getActionBar();
+               ActionBar actionBar = getSupportActionBar();
                actionBar.setDisplayHomeAsUpEnabled(true);
-               actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
-
-               TrustedCertificatesTabListener listener;
-               listener = new TrustedCertificatesTabListener(this, "system", TrustedCertificateSource.SYSTEM);
-               actionBar.addTab(actionBar
-                       .newTab()
-                       .setText(R.string.system_tab)
-                       .setTag(listener)
-                       .setTabListener(listener));
-               listener = new TrustedCertificatesTabListener(this, "user", TrustedCertificateSource.USER);
-               actionBar.addTab(actionBar
-                       .newTab()
-                       .setText(R.string.user_tab)
-                       .setTag(listener)
-                       .setTabListener(listener));
-               listener = new TrustedCertificatesTabListener(this, "local", TrustedCertificateSource.LOCAL);
-               actionBar.addTab(actionBar
-                       .newTab()
-                       .setText(R.string.local_tab)
-                       .setTag(listener)
-                       .setTabListener(listener));
-
-               if (savedInstanceState != null)
-               {
-                       actionBar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
-               }
-               mSelect = SELECT_CERTIFICATE.equals(getIntent().getAction());
-       }
 
-       @Override
-       protected void onSaveInstanceState(Bundle outState)
-       {
-               super.onSaveInstanceState(outState);
-               outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
+               mAdapter = new TrustedCertificatesPagerAdapter(getSupportFragmentManager(), this);
+
+               mPager = (ViewPager)findViewById(R.id.viewpager);
+               mPager.setAdapter(mAdapter);
+
+               TabLayout tabs = (TabLayout)findViewById(R.id.tabs);
+               tabs.setupWithViewPager(mPager);
+
+               mSelect = SELECT_CERTIFICATE.equals(getIntent().getAction());
        }
 
        @Override
@@ -148,18 +130,13 @@ public class TrustedCertificatesActivity extends Activity implements TrustedCert
                        setResult(Activity.RESULT_OK, intent);
                        finish();
                }
-               else
+               else if (mAdapter.getSource(mPager.getCurrentItem()) == TrustedCertificateSource.LOCAL)
                {
-                       TrustedCertificatesTabListener listener;
-                       listener = (TrustedCertificatesTabListener)getActionBar().getSelectedTab().getTag();
-                       if (listener.mTag == "local")
-                       {
-                               Bundle args = new Bundle();
-                               args.putString(CertificateDeleteConfirmationDialog.ALIAS, selected.getAlias());
-                               CertificateDeleteConfirmationDialog dialog = new CertificateDeleteConfirmationDialog();
-                               dialog.setArguments(args);
-                               dialog.show(this.getFragmentManager(), DIALOG_TAG);
-                       }
+                       Bundle args = new Bundle();
+                       args.putString(CertificateDeleteConfirmationDialog.ALIAS, selected.getAlias());
+                       CertificateDeleteConfirmationDialog dialog = new CertificateDeleteConfirmationDialog();
+                       dialog.setArguments(args);
+                       dialog.show(getSupportFragmentManager(), DIALOG_TAG);
                }
        }
 
@@ -182,74 +159,69 @@ public class TrustedCertificatesActivity extends Activity implements TrustedCert
        private void reloadCertificates()
        {
                TrustedCertificateManager.getInstance().reset();
-               for (int i = 0; i < getActionBar().getTabCount(); i++)
-               {
-                       Tab tab = getActionBar().getTabAt(i);
-                       TrustedCertificatesTabListener listener = (TrustedCertificatesTabListener)tab.getTag();
-                       listener.reset();
-               }
        }
 
-       public static class TrustedCertificatesTabListener implements ActionBar.TabListener
+       public static class TrustedCertificatesPagerAdapter extends FragmentPagerAdapter
        {
-               private final String mTag;
-               private final TrustedCertificateSource mSource;
-               private Fragment mFragment;
+               private TrustedCertificatesTab mTabs[];
 
-               public TrustedCertificatesTabListener(Activity activity, String tag, TrustedCertificateSource source)
+               public TrustedCertificatesPagerAdapter(FragmentManager fm, Context context)
                {
-                       mTag = tag;
-                       mSource = source;
-                       /* check to see if we already have a fragment for this tab, probably
-                        * from a previously saved state. if so, deactivate it, because the
-                        * initial state is that no tab is shown */
-                       mFragment = activity.getFragmentManager().findFragmentByTag(mTag);
-                       if (mFragment != null && !mFragment.isDetached())
-                       {
-                               FragmentTransaction ft = activity.getFragmentManager().beginTransaction();
-                               ft.detach(mFragment);
-                               ft.commit();
-                       }
+                       super(fm);
+                       mTabs = new TrustedCertificatesTab[]{
+                               new TrustedCertificatesTab(context.getString(R.string.system_tab), TrustedCertificateSource.SYSTEM),
+                               new TrustedCertificatesTab(context.getString(R.string.user_tab), TrustedCertificateSource.USER),
+                               new TrustedCertificatesTab(context.getString(R.string.local_tab), TrustedCertificateSource.LOCAL),
+                       };
                }
 
                @Override
-               public void onTabSelected(Tab tab, FragmentTransaction ft)
+               public int getCount()
                {
-                       if (mFragment == null)
-                       {
-                               mFragment = new TrustedCertificateListFragment();
-                               Bundle args = new Bundle();
-                               args.putSerializable(TrustedCertificateListFragment.EXTRA_CERTIFICATE_SOURCE, mSource);
-                               mFragment.setArguments(args);
-                               ft.add(android.R.id.content, mFragment, mTag);
-                       }
-                       else
-                       {
-                               ft.attach(mFragment);
-                       }
+                       return mTabs.length;
                }
 
                @Override
-               public void onTabUnselected(Tab tab, FragmentTransaction ft)
+               public CharSequence getPageTitle(int position)
                {
-                       if (mFragment != null)
-                       {
-                               ft.detach(mFragment);
-                       }
+                       return mTabs[position].getTitle();
+               }
+
+               public TrustedCertificateSource getSource(int position)
+               {
+                       return mTabs[position].getSource();
                }
 
                @Override
-               public void onTabReselected(Tab tab, FragmentTransaction ft)
+               public Fragment getItem(int position)
+               {
+                       TrustedCertificateListFragment fragment = new TrustedCertificateListFragment();
+                       Bundle args = new Bundle();
+                       args.putSerializable(TrustedCertificateListFragment.EXTRA_CERTIFICATE_SOURCE, mTabs[position].getSource());
+                       fragment.setArguments(args);
+                       return fragment;
+               }
+       }
+
+       public static class TrustedCertificatesTab
+       {
+               private final String mTitle;
+               private final TrustedCertificateSource mSource;
+
+               public TrustedCertificatesTab(String title, TrustedCertificateSource source)
+               {
+                       mTitle = title;
+                       mSource = source;
+               }
+
+               public String getTitle()
                {
-                       /* nothing to be done */
+                       return mTitle;
                }
 
-               public void reset()
+               public TrustedCertificateSource getSource()
                {
-                       if (mFragment != null)
-                       {
-                               ((TrustedCertificateListFragment)mFragment).reset();
-                       }
+                       return mSource;
                }
        }
 }
index a8b3daa..bcc226b 100644 (file)
 
 package org.strongswan.android.ui;
 
-import java.security.cert.X509Certificate;
-
-import org.strongswan.android.R;
-import org.strongswan.android.data.VpnProfile;
-import org.strongswan.android.data.VpnProfileDataSource;
-import org.strongswan.android.data.VpnType;
-import org.strongswan.android.data.VpnType.VpnTypeFeature;
-import org.strongswan.android.logic.TrustedCertificateManager;
-import org.strongswan.android.security.TrustedCertificateEntry;
-
-import android.app.Activity;
-import android.app.AlertDialog;
 import android.app.Dialog;
-import android.app.DialogFragment;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -39,6 +26,9 @@ import android.os.Bundle;
 import android.security.KeyChain;
 import android.security.KeyChainAliasCallback;
 import android.security.KeyChainException;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.app.AppCompatDialogFragment;
 import android.text.Html;
 import android.util.Log;
 import android.view.Menu;
@@ -57,7 +47,17 @@ import android.widget.RelativeLayout;
 import android.widget.Spinner;
 import android.widget.TextView;
 
-public class VpnProfileDetailActivity extends Activity
+import org.strongswan.android.R;
+import org.strongswan.android.data.VpnProfile;
+import org.strongswan.android.data.VpnProfileDataSource;
+import org.strongswan.android.data.VpnType;
+import org.strongswan.android.data.VpnType.VpnTypeFeature;
+import org.strongswan.android.logic.TrustedCertificateManager;
+import org.strongswan.android.security.TrustedCertificateEntry;
+
+import java.security.cert.X509Certificate;
+
+public class VpnProfileDetailActivity extends AppCompatActivity
 {
        private static final int SELECT_TRUSTED_CERTIFICATE = 0;
        private static final int MTU_MIN = 1280;
@@ -94,7 +94,7 @@ public class VpnProfileDetailActivity extends Activity
                super.onCreate(savedInstanceState);
 
                /* the title is set when we load the profile, if any */
-               getActionBar().setDisplayHomeAsUpEnabled(true);
+               getSupportActionBar().setDisplayHomeAsUpEnabled(true);
 
                mDataSource = new VpnProfileDataSource(this);
                mDataSource.open();
@@ -146,7 +146,7 @@ public class VpnProfileDetailActivity extends Activity
                        @Override
                        public void onClick(View v)
                        {
-                               new TncNoticeDialog().show(VpnProfileDetailActivity.this.getFragmentManager(), "TncNotice");
+                               new TncNoticeDialog().show(VpnProfileDetailActivity.this.getSupportFragmentManager(), "TncNotice");
                        }
                });
 
@@ -465,7 +465,7 @@ public class VpnProfileDetailActivity extends Activity
        {
                String useralias = null, alias = null;
 
-               getActionBar().setTitle(R.string.add_profile);
+               getSupportActionBar().setTitle(R.string.add_profile);
                if (mId != null && mId != 0)
                {
                        mProfile = mDataSource.getVpnProfile(mId);
@@ -482,7 +482,7 @@ public class VpnProfileDetailActivity extends Activity
                                mBlockIPv6.setChecked(mProfile.getSplitTunneling() != null ? (mProfile.getSplitTunneling() & VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6) != 0 : false);
                                useralias = mProfile.getUserCertificateAlias();
                                alias = mProfile.getCertificateAlias();
-                               getActionBar().setTitle(mProfile.getName());
+                               getSupportActionBar().setTitle(mProfile.getName());
                        }
                        else
                        {
@@ -633,7 +633,7 @@ public class VpnProfileDetailActivity extends Activity
        /**
         * Dialog with notification message if EAP-TNC is used.
         */
-       public static class TncNoticeDialog extends DialogFragment
+       public static class TncNoticeDialog extends AppCompatDialogFragment
        {
                @Override
                public Dialog onCreateDialog(Bundle savedInstanceState)
index fb684b5..a23df05 100644 (file)
@@ -109,15 +109,13 @@ public class VpnProfileListFragment extends Fragment
                        setHasOptionsMenu(true);
                }
 
-               Context context = getActivity().getApplicationContext();
-
                mDataSource = new VpnProfileDataSource(this.getActivity());
                mDataSource.open();
 
                /* cached list of profiles used as backend for the ListView */
                mVpnProfiles = mDataSource.getAllVpnProfiles();
 
-               mListAdapter = new VpnProfileAdapter(context, R.layout.profile_list_item, mVpnProfiles);
+               mListAdapter = new VpnProfileAdapter(getActivity(), R.layout.profile_list_item, mVpnProfiles);
        }
 
        @Override
index b4d34f5..23b66d3 100644 (file)
 
 package org.strongswan.android.ui;
 
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
 import org.strongswan.android.R;
 import org.strongswan.android.data.VpnProfile;
 import org.strongswan.android.ui.VpnProfileListFragment.OnVpnProfileSelectedListener;
 
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-
-public class VpnProfileSelectActivity extends Activity implements OnVpnProfileSelectedListener
+public class VpnProfileSelectActivity extends AppCompatActivity implements OnVpnProfileSelectedListener
 {
        @Override
        protected void onCreate(Bundle savedInstanceState)
index 160ba95..c49e5cc 100644 (file)
 
 package org.strongswan.android.ui;
 
-import java.util.ArrayList;
-import java.util.List;
-
-import org.strongswan.android.R;
-import org.strongswan.android.data.VpnProfile;
-import org.strongswan.android.logic.VpnStateService;
-import org.strongswan.android.logic.VpnStateService.ErrorState;
-import org.strongswan.android.logic.VpnStateService.State;
-import org.strongswan.android.logic.VpnStateService.VpnStateListener;
-import org.strongswan.android.logic.imc.ImcState;
-import org.strongswan.android.logic.imc.RemediationInstruction;
-
-import android.app.AlertDialog;
 import android.app.Fragment;
 import android.app.ProgressDialog;
 import android.app.Service;
@@ -40,6 +27,8 @@ import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.AlertDialog;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -47,6 +36,18 @@ import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.TextView;
 
+import org.strongswan.android.R;
+import org.strongswan.android.data.VpnProfile;
+import org.strongswan.android.logic.VpnStateService;
+import org.strongswan.android.logic.VpnStateService.ErrorState;
+import org.strongswan.android.logic.VpnStateService.State;
+import org.strongswan.android.logic.VpnStateService.VpnStateListener;
+import org.strongswan.android.logic.imc.ImcState;
+import org.strongswan.android.logic.imc.RemediationInstruction;
+
+import java.util.ArrayList;
+import java.util.List;
+
 public class VpnStateFragment extends Fragment implements VpnStateListener
 {
        private static final String KEY_ERROR_CONNECTION_ID = "error_connection_id";
@@ -55,7 +56,9 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
        private TextView mProfileNameView;
        private TextView mProfileView;
        private TextView mStateView;
-       private int stateBaseColor;
+       private int mColorStateBase;
+       private int mColorStateError;
+       private int mColorStateSuccess;
        private Button mActionButton;
        private ProgressDialog mConnectDialog;
        private ProgressDialog mDisconnectDialog;
@@ -64,7 +67,8 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
        private long mErrorConnectionID;
        private long mDismissedConnectionID;
        private VpnStateService mService;
-       private final ServiceConnection mServiceConnection = new ServiceConnection() {
+       private final ServiceConnection mServiceConnection = new ServiceConnection()
+       {
                @Override
                public void onServiceDisconnected(ComponentName name)
                {
@@ -85,6 +89,9 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
        {
                super.onCreate(savedInstanceState);
 
+               mColorStateError = ContextCompat.getColor(getActivity(), R.color.error_text);
+               mColorStateSuccess = ContextCompat.getColor(getActivity(), R.color.success_text);
+
                /* bind to the service only seems to work from the ApplicationContext */
                Context context = getActivity().getApplicationContext();
                context.bindService(new Intent(context, VpnStateService.class),
@@ -115,7 +122,8 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
                View view = inflater.inflate(R.layout.vpn_state_fragment, null);
 
                mActionButton = (Button)view.findViewById(R.id.action);
-               mActionButton.setOnClickListener(new OnClickListener() {
+               mActionButton.setOnClickListener(new OnClickListener()
+               {
                        @Override
                        public void onClick(View v)
                        {
@@ -128,7 +136,7 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
                enableActionButton(false);
 
                mStateView = (TextView)view.findViewById(R.id.vpn_state);
-               stateBaseColor = mStateView.getCurrentTextColor();
+               mColorStateBase = mStateView.getCurrentTextColor();
                mProfileView = (TextView)view.findViewById(R.id.vpn_profile_label);
                mProfileNameView = (TextView)view.findViewById(R.id.vpn_profile_name);
 
@@ -203,26 +211,26 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
                                showProfile(false);
                                hideProgressDialog();
                                mStateView.setText(R.string.state_disabled);
-                               mStateView.setTextColor(stateBaseColor);
+                               mStateView.setTextColor(mColorStateBase);
                                break;
                        case CONNECTING:
                                showProfile(true);
                                showConnectDialog(name, gateway);
                                mStateView.setText(R.string.state_connecting);
-                               mStateView.setTextColor(stateBaseColor);
+                               mStateView.setTextColor(mColorStateBase);
                                break;
                        case CONNECTED:
                                showProfile(true);
                                hideProgressDialog();
                                enableActionButton(true);
                                mStateView.setText(R.string.state_connected);
-                               mStateView.setTextColor(getResources().getColor(R.color.success_text));
+                               mStateView.setTextColor(mColorStateSuccess);
                                break;
                        case DISCONNECTING:
                                showProfile(true);
                                showDisconnectDialog(name);
                                mStateView.setText(R.string.state_disconnecting);
-                               mStateView.setTextColor(stateBaseColor);
+                               mStateView.setTextColor(mColorStateBase);
                                break;
                }
        }
@@ -251,7 +259,7 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
                showProfile(true);
                enableActionButton(false);
                mStateView.setText(R.string.state_error);
-               mStateView.setTextColor(getResources().getColor(R.color.error_text));
+               mStateView.setTextColor(mColorStateError);
                switch (error)
                {
                        case AUTH_FAILED:
@@ -334,18 +342,18 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
                mConnectDialog.setIndeterminate(true);
                mConnectDialog.setCancelable(false);
                mConnectDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
-                         getString(android.R.string.cancel),
-                         new DialogInterface.OnClickListener()
-                         {
-                                 @Override
-                                 public void onClick(DialogInterface dialog, int which)
-                                 {
-                                         if (mService != null)
-                                         {
-                                                 mService.disconnect();
-                                         }
-                                 }
-                         });
+                                                                getString(android.R.string.cancel),
+                                                                new DialogInterface.OnClickListener()
+                                                                {
+                                                                        @Override
+                                                                        public void onClick(DialogInterface dialog, int which)
+                                                                        {
+                                                                                if (mService != null)
+                                                                                {
+                                                                                        mService.disconnect();
+                                                                                }
+                                                                        }
+                                                                });
                mConnectDialog.show();
                mProgressDialog = mConnectDialog;
        }
@@ -374,7 +382,8 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
                mErrorDialog = new AlertDialog.Builder(getActivity())
                        .setMessage(getString(R.string.error_introduction) + " " + getString(textid))
                        .setCancelable(false)
-                       .setNeutralButton(text, new DialogInterface.OnClickListener() {
+                       .setNeutralButton(text, new DialogInterface.OnClickListener()
+                       {
                                @Override
                                public void onClick(DialogInterface dialog, int which)
                                {
@@ -394,7 +403,8 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
                                        startActivity(intent);
                                }
                        })
-                       .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                       .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
+                       {
                                @Override
                                public void onClick(DialogInterface dialog, int id)
                                {
@@ -402,7 +412,8 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
                                        dialog.dismiss();
                                }
                        }).create();
-               mErrorDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+               mErrorDialog.setOnDismissListener(new DialogInterface.OnDismissListener()
+               {
                        @Override
                        public void onDismiss(DialogInterface dialog)
                        {
diff --git a/src/frontends/android/app/src/main/res/drawable/activated_background.xml b/src/frontends/android/app/src/main/res/drawable/activated_background.xml
new file mode 100644 (file)
index 0000000..04cf6ef
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2016 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_pressed="true"
+        android:drawable="@color/pressed" />
+
+    <item
+        android:state_activated="true"
+        android:drawable="@color/accent" />
+
+    <item
+        android:drawable="@android:color/transparent" />
+
+</selector>
index c2e187a..601c0a5 100644 (file)
@@ -33,7 +33,8 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textSize="9sp"
-            android:typeface="monospace" >
+            android:typeface="monospace"
+            android:fontFamily="monospace" >
         </TextView>
 
     </org.strongswan.android.ui.LogScrollView>
index 966ecf2..aeefd81 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-    Copyright (C) 2012 Tobias Brunner
+    Copyright (C) 2012-2015 Tobias Brunner
     Hochschule fuer Technik Rapperswil
 
     This program is free software; you can redistribute it and/or modify it
     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     for more details.
 -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent" >
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:app="http://schemas.android.com/apk/res-auto"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
 
-</FrameLayout>
+    <android.support.design.widget.TabLayout
+        android:id="@+id/tabs"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:tabGravity="fill"
+        app:tabMode="fixed"/>
+
+    <android.support.v4.view.ViewPager
+        android:id="@+id/viewpager"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"/>
+
+</LinearLayout>
index 6066cab..8ce4f62 100644 (file)
     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     for more details.
 -->
-<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <item
         android:id="@+id/menu_import_certificate"
         android:title="@string/import_certificate"
-        android:showAsAction="withText" />
+        app:showAsAction="withText" />
 
     <item
         android:id="@+id/menu_reload_certs"
         android:title="@string/reload_trusted_certs"
-        android:showAsAction="withText" />
+        app:showAsAction="withText" />
 
 </menu>
index 1af5bd3..cb4c84a 100644 (file)
     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     for more details.
 -->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <item
         android:id="@+id/menu_send_log"
         android:title="@string/send_log"
-        android:showAsAction="ifRoom|withText" />
+        app:showAsAction="ifRoom|withText" />
 
 </menu>
index 3dde522..599254a 100644 (file)
     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     for more details.
 -->
-<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <item
         android:id="@+id/menu_manage_certs"
         android:title="@string/trusted_certs_title"
-        android:showAsAction="withText" />
+        app:showAsAction="withText" />
 
     <item
         android:id="@+id/menu_show_log"
         android:title="@string/show_log"
-        android:showAsAction="withText" />
+        app:showAsAction="withText" />
 
-</menu>
\ No newline at end of file
+</menu>
index e69020e..280f34d 100644 (file)
     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     for more details.
 -->
-<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <item
         android:id="@+id/menu_accept"
         android:title="@string/profile_edit_save"
-        android:showAsAction="always|withText" />
+        app:showAsAction="always|withText" />
 
     <item
         android:id="@+id/menu_cancel"
         android:title="@string/profile_edit_cancel"
-        android:showAsAction="ifRoom" />
+        app:showAsAction="ifRoom" />
 
 </menu>
index 57c9a86..8f8838f 100644 (file)
     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     for more details.
 -->
-<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <item android:id="@+id/add_profile"
         android:title="@string/add_profile"
-        android:showAsAction="always|withText" />
+        app:showAsAction="always|withText" />
 
 </menu>
index e674ae8..1d6a3dc 100644 (file)
@@ -16,9 +16,9 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <item android:id="@+id/edit_profile"
-        android:title="@string/edit_profile" ></item>
+        android:title="@string/edit_profile" />
 
     <item android:id="@+id/delete_profile"
-        android:title="@string/delete_profile" ></item>
+        android:title="@string/delete_profile" />
 
-</menu>
\ No newline at end of file
+</menu>
index 6cd5ba5..8b6ff95 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-    Copyright (C) 2012-2015 Tobias Brunner
+    Copyright (C) 2012-2016 Tobias Brunner
     Copyright (C) 2012 Giuliano Grassi
     Copyright (C) 2012 Ralf Sager
-    Hochschule fuer Technik Rapperswil
+    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
@@ -50,8 +50,8 @@
     <string name="profile_edit_save">Speichern</string>
     <string name="profile_edit_cancel">Abbrechen</string>
     <string name="profile_name_label">Profilname:</string>
-    <string name="profile_name_hint">(Gateway-Adresse verwenden)</string>
-    <string name="profile_gateway_label">Gateway:</string>
+    <string name="profile_name_hint">(Server-Adresse verwenden)</string>
+    <string name="profile_gateway_label">Server:</string>
     <string name="profile_vpn_type_label">Typ:</string>
     <string name="profile_username_label">Benutzername:</string>
     <string name="profile_password_label">Passwort:</string>
     <string name="profile_split_tunnelingv4_title">Blockiere IPv4 Verkehr der nicht für das VPN bestimmt ist</string>
     <string name="profile_split_tunnelingv6_title">Blockiere IPv6 Verkehr der nicht für das VPN bestimmt ist</string>
     <!-- Warnings/Notifications in the details view -->
-    <string name="alert_text_no_input_gateway">Bitte geben Sie hier die Gateway-Adresse ein</string>
+    <string name="alert_text_no_input_gateway">Bitte geben Sie hier die Server-Adresse ein</string>
     <string name="alert_text_no_input_username">Bitte geben Sie hier Ihren Benutzernamen ein</string>
     <string name="alert_text_nocertfound_title">Kein CA-Zertifikat ausgewählt</string>
     <string name="alert_text_nocertfound">Bitte wählen Sie eines aus oder aktivieren Sie <i>Automatisch wählen</i></string>
     <string name="alert_text_out_of_range">Bitte geben Sie eine Nummer von %1$d - %2$d ein</string>
     <string name="tnc_notice_title">EAP-TNC kann Ihre Privatsphäre beeinträchtigen</string>
-    <string name="tnc_notice_subtitle">Gerätedaten werden an den Gateway-Betreiber gesendet</string>
-    <string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) erlaubt Gateway-Betreibern den Gesundheitszustand von Endgeräten zu prüfen.&lt;/p>&lt;p>Dazu kann der Betreiber Daten verlangen, wie etwa eine eindeutige Identifikationsnummer, eine Liste der installierten Pakete, Systemeinstellungen oder kryptografische Prüfsummen von Dateien.&lt;/p>&lt;b>Solche Daten werden nur übermittelt nachdem die Identität des Gateways geprüft wurde.&lt;/b></string>
+    <string name="tnc_notice_subtitle">Gerätedaten werden an den Server-Betreiber gesendet</string>
+    <string name="tnc_notice_details"><![CDATA[<p>Trusted Network Connect (TNC) erlaubt Server-Betreibern den Gesundheitszustand von Endgeräten zu prüfen.</p><p>Dazu kann der Betreiber Daten verlangen, wie etwa eine eindeutige Identifikationsnummer, eine Liste der installierten Pakete, Systemeinstellungen oder kryptografische Prüfsummen von Dateien.</p><b>Solche Daten werden nur übermittelt nachdem die Identität des Servers geprüft wurde.</b>]]></string>
 
     <!-- Trusted certificate selection -->
     <string name="trusted_certs_title">CA-Zertifikate</string>
     <string name="login_title">Passwort eingeben um zu verbinden</string>
     <string name="login_confirm">Verbinden</string>
     <string name="error_introduction">Fehler beim Aufsetzen des VPN:</string>
-    <string name="error_lookup_failed">Gateway-Adresse konnte nicht aufgelöst werden.</string>
-    <string name="error_unreachable">Gateway ist nicht erreichbar.</string>
-    <string name="error_peer_auth_failed">Authentifizierung des Gateway ist fehlgeschlagen.</string>
+    <string name="error_lookup_failed">Server-Adresse konnte nicht aufgelöst werden.</string>
+    <string name="error_unreachable">Server ist nicht erreichbar.</string>
+    <string name="error_peer_auth_failed">Authentifizierung des Servers ist fehlgeschlagen.</string>
     <string name="error_auth_failed">Benutzerauthentifizierung ist fehlgeschlagen.</string>
     <string name="error_assessment_failed">Sicherheitsassessment ist fehlgeschlagen.</string>
     <string name="error_generic">Unbekannter Fehler während des Verbindens.</string>
index fb2aba0..2638719 100644 (file)
@@ -50,8 +50,8 @@
     <string name="profile_edit_save">Zapisz</string>
     <string name="profile_edit_cancel">Anuluj</string>
     <string name="profile_name_label">Nazwa profilu:</string>
-    <string name="profile_name_hint">(użyj adresu bramki)</string>
-    <string name="profile_gateway_label">Bramka:</string>
+    <string name="profile_name_hint">(użyj adresu serwer)</string>
+    <string name="profile_gateway_label">Serwer:</string>
     <string name="profile_vpn_type_label">Typ:</string>
     <string name="profile_username_label">Użytkownik:</string>
     <string name="profile_password_label">Hasło:</string>
     <string name="profile_split_tunnelingv4_title">Block IPv4 traffic not destined for the VPN</string>
     <string name="profile_split_tunnelingv6_title">Block IPv6 traffic not destined for the VPN</string>
     <!-- Warnings/Notifications in the details view -->
-    <string name="alert_text_no_input_gateway">Wprowadź adres bramki</string>
+    <string name="alert_text_no_input_gateway">Wprowadź adres serwer</string>
     <string name="alert_text_no_input_username">Wprowadź swoją nazwę użytkownika</string>
     <string name="alert_text_nocertfound_title">Nie wybrano żadnego certyfikatu CA</string>
     <string name="alert_text_nocertfound">Wybierz lub uaktywnij jeden <i>Wybierz automatycznie</i></string>
     <string name="alert_text_out_of_range">Please enter a number in the range from %1$d - %2$d</string>
     <string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
-    <string name="tnc_notice_subtitle">Device data is sent to the gateway operator</string>
-    <string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows gateway operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the gateway operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the gateway\'s identity.&lt;/b></string>
+    <string name="tnc_notice_subtitle">Device data is sent to the server operator</string>
+    <string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows server operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the server operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the server\'s identity.&lt;/b></string>
 
     <!-- Trusted certificate selection -->
     <string name="trusted_certs_title">Certyfikaty CA</string>
     <string name="login_title">Wprowadż hasło</string>
     <string name="login_confirm">Połącz</string>
     <string name="error_introduction">Nie udało się utworzyć tunelu VPN:</string>
-    <string name="error_lookup_failed">Nie znaleziono adresu bramki</string>
-    <string name="error_unreachable">Bramka jest nieosiągalna</string>
-    <string name="error_peer_auth_failed">Błąd przy weryfikacji bramki</string>
+    <string name="error_lookup_failed">Nie znaleziono adresu serwer</string>
+    <string name="error_unreachable">Serwer jest nieosiągalna</string>
+    <string name="error_peer_auth_failed">Błąd przy weryfikacji serwer</string>
     <string name="error_auth_failed">Błąd przy autoryzacji użytkownika</string>
     <string name="error_assessment_failed">Security assessment failed.</string>
     <string name="error_generic">Nieznany błąd w czasie połączenia</string>
index eabfc08..ec9d663 100644 (file)
@@ -47,8 +47,8 @@
     <string name="profile_edit_save">Сохранить</string>
     <string name="profile_edit_cancel">Отмена</string>
     <string name="profile_name_label">Название профиля:</string>
-    <string name="profile_name_hint">(адрес шлюза)</string>
-    <string name="profile_gateway_label">ШлÑ\8eз:</string>
+    <string name="profile_name_hint">(адрес cервер)</string>
+    <string name="profile_gateway_label">СеÑ\80веÑ\80:</string>
     <string name="profile_vpn_type_label">Тип:</string>
     <string name="profile_username_label">Логин:</string>
     <string name="profile_password_label">Пароль:</string>
     <string name="profile_split_tunnelingv4_title">Block IPv4 traffic not destined for the VPN</string>
     <string name="profile_split_tunnelingv6_title">Block IPv6 traffic not destined for the VPN</string>
     <!-- Warnings/Notifications in the details view -->
-    <string name="alert_text_no_input_gateway">Пожалуйста введите адрес шлюза</string>
+    <string name="alert_text_no_input_gateway">Пожалуйста введите адрес cервер</string>
     <string name="alert_text_no_input_username">Пожалуйста введите имя пользователя</string>
     <string name="alert_text_nocertfound_title">Не выбран сертификат CA</string>
     <string name="alert_text_nocertfound">Пожалуйста выберите один <i>Выбрать автоматически</i></string>
     <string name="alert_text_out_of_range">Please enter a number in the range from %1$d - %2$d</string>
     <string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
-    <string name="tnc_notice_subtitle">Device data is sent to the gateway operator</string>
-    <string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows gateway operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the gateway operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the gateway\'s identity.&lt;/b></string>
+    <string name="tnc_notice_subtitle">Device data is sent to the server operator</string>
+    <string name="tnc_notice_details"><![CDATA[<p>Trusted Network Connect (TNC) allows server operators to assess the health of a client device.</p><p>For that purpose the server operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.</p><b>Any data will be sent only after verifying the server\'s identity.</b>]]></string>
 
     <!-- Trusted certificate selection -->
     <string name="trusted_certs_title">Сертификаты CA</string>
     <string name="login_title">Введите пароль для соединения</string>
     <string name="login_confirm">Соединить</string>
     <string name="error_introduction">Ошибка подключения к VPN:</string>
-    <string name="error_lookup_failed">Ð\9dе Ð½Ð°Ð¹Ð´ÐµÐ½ Ð°Ð´Ñ\80еÑ\81 Ñ\88лÑ\8eза.</string>
-    <string name="error_unreachable">ШлÑ\8eз недоступен.</string>
-    <string name="error_peer_auth_failed">Ð\9eÑ\88ибка Ð°Ð²Ñ\82оÑ\80изаÑ\86и Ð¿Ñ\80и Ð¿Ð¾Ð´ÐºÐ»Ñ\8eÑ\87ении Ðº Ñ\88лÑ\8eзÑ\83.</string>
+    <string name="error_lookup_failed">Ð\9dе Ð½Ð°Ð¹Ð´ÐµÐ½ Ð°Ð´Ñ\80еÑ\81 Ñ\81еÑ\80веÑ\80.</string>
+    <string name="error_unreachable">СеÑ\80веÑ\80 недоступен.</string>
+    <string name="error_peer_auth_failed">Ð\9eÑ\88ибка Ð°Ð²Ñ\82оÑ\80изаÑ\86и Ð¿Ñ\80и Ð¿Ð¾Ð´ÐºÐ»Ñ\8eÑ\87ении Ðº Ñ\81еÑ\80веÑ\80.</string>
     <string name="error_auth_failed">Ошибка авторизации пользователя.</string>
     <string name="error_assessment_failed">Security assessment failed.</string>
     <string name="error_generic">Неизвестная ошибка.</string>
index d7c2383..a5e668b 100644 (file)
@@ -48,8 +48,8 @@
     <string name="profile_edit_save">Зберегти</string>
     <string name="profile_edit_cancel">Відміна</string>
     <string name="profile_name_label">Назва профілю:</string>
-    <string name="profile_name_hint">(використовувати адресу шлюза)</string>
-    <string name="profile_gateway_label">ШлÑ\8eз:</string>
+    <string name="profile_name_hint">(використовувати адресу cервер)</string>
+    <string name="profile_gateway_label">СеÑ\80веÑ\80:</string>
     <string name="profile_vpn_type_label">Тип:</string>
     <string name="profile_username_label">Логін:</string>
     <string name="profile_password_label">Пароль:</string>
     <string name="profile_split_tunnelingv4_title">Block IPv4 traffic not destined for the VPN</string>
     <string name="profile_split_tunnelingv6_title">Block IPv6 traffic not destined for the VPN</string>
     <!-- Warnings/Notifications in the details view -->
-    <string name="alert_text_no_input_gateway">Введіть адресу шлюза тут</string>
+    <string name="alert_text_no_input_gateway">Введіть адресу cервер тут</string>
     <string name="alert_text_no_input_username">Введіть ім\'я користувача тут</string>
     <string name="alert_text_nocertfound_title">Не вибрано сертифікат CA</string>
     <string name="alert_text_nocertfound">Будь ласка виберіть один <i>Вибрати автоматично</i></string>
     <string name="alert_text_out_of_range">Please enter a number in the range from %1$d - %2$d</string>
     <string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
-    <string name="tnc_notice_subtitle">Device data is sent to the gateway operator</string>
-    <string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows gateway operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the gateway operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the gateway\'s identity.&lt;/b></string>
+    <string name="tnc_notice_subtitle">Device data is sent to the server operator</string>
+    <string name="tnc_notice_details"><![CDATA[<p>Trusted Network Connect (TNC) allows server operators to assess the health of a client device.</p><p>For that purpose the server operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.</p><b>Any data will be sent only after verifying the server\'s identity.</b>]]></string>
 
     <!-- Trusted certificate selection -->
     <string name="trusted_certs_title">Сертифікати CA</string>
     <string name="login_title">Введіть пароль для з\'єднання</string>
     <string name="login_confirm">Підключити</string>
     <string name="error_introduction">Помилка підлючення VPN:</string>
-    <string name="error_lookup_failed">Ð\9fомилка Ð¿Ð¾Ñ\88Ñ\83кÑ\83 Ð°Ð´Ñ\80еÑ\81и Ñ\88лÑ\8eза.</string>
-    <string name="error_unreachable">Ð\9dемаÑ\94 зв\'язку зі шлюзом.</string>
-    <string name="error_peer_auth_failed">Ð\9fомилка Ð¿ÐµÑ\80евÑ\96Ñ\80ки Ð´Ð°Ð½Ð½Ð¸Ñ\85 Ð°Ñ\83Ñ\82енÑ\82иÑ\84Ñ\96каÑ\86Ñ\96Ñ\97 Ñ\88лÑ\8eза.</string>
+    <string name="error_lookup_failed">Ð\9fомилка Ð¿Ð¾Ñ\88Ñ\83кÑ\83 Ð°Ð´Ñ\80еÑ\81и Ñ\81еÑ\80веÑ\80.</string>
+    <string name="error_unreachable">СеÑ\80веÑ\80 зв\'язку зі шлюзом.</string>
+    <string name="error_peer_auth_failed">Ð\9fомилка Ð¿ÐµÑ\80евÑ\96Ñ\80ки Ð´Ð°Ð½Ð½Ð¸Ñ\85 Ð°Ñ\83Ñ\82енÑ\82иÑ\84Ñ\96каÑ\86Ñ\96Ñ\97 Ñ\81еÑ\80веÑ\80.</string>
     <string name="error_auth_failed">Помилка аутентифікації користувача.</string>
     <string name="error_assessment_failed">Security assessment failed.</string>
     <string name="error_generic">Невідома помилка під час підключення.</string>
diff --git a/src/frontends/android/app/src/main/res/values-v15/styles.xml b/src/frontends/android/app/src/main/res/values-v15/styles.xml
new file mode 100644 (file)
index 0000000..bf40c3f
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2016 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.
+-->
+<resources>
+
+    <style name="ApplicationTheme" parent="ApplicationTheme.Base">
+        <item name="android:activatedBackgroundIndicator">@drawable/activated_background</item>
+        <item name="android:selectableItemBackground">@drawable/activated_background</item>
+    </style>
+
+    <style name="AlertDialogTheme" parent="AlertDialogTheme.Base">
+        <item name="android:windowBackground">@android:color/transparent</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/src/frontends/android/app/src/main/res/values-v21/styles.xml b/src/frontends/android/app/src/main/res/values-v21/styles.xml
new file mode 100644 (file)
index 0000000..32de06b
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2016 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.
+-->
+<resources>
+
+    <style name="ApplicationTheme" parent="ApplicationTheme.Base">
+    </style>
+
+    <style name="AlertDialogTheme" parent="AlertDialogTheme.Base">
+    </style>
+
+</resources>
\ No newline at end of file
index 4af28b4..f29ae19 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-    Copyright (C) 2012-2013 Tobias Brunner
-    Hochschule fuer Technik Rapperswil
+    Copyright (C) 2012-2016 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
 <resources>
 
     <color
+        name="accent">#96BDC2</color>
+
+    <color
+        name="primary">#A2042C</color>
+
+    <color
+        name="primary_dark">#000000</color>
+
+    <color
         name="error_text">#D9192C</color>
 
     <color
         name="success_text">#99CC00</color>
 
     <color
-        name="panel_background">#333333</color>
+        name="panel_background">#444444</color>
 
     <color
         name="panel_separator">#5a5a5a</color>
 
+    <color
+        name="pressed">#5a5a5a</color>
+
 </resources>
index 5c8ebab..2b0049f 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-    Copyright (C) 2012-2015 Tobias Brunner
+    Copyright (C) 2012-2016 Tobias Brunner
     Copyright (C) 2012 Giuliano Grassi
     Copyright (C) 2012 Ralf Sager
-    Hochschule fuer Technik Rapperswil
+    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
@@ -50,8 +50,8 @@
     <string name="profile_edit_save">Save</string>
     <string name="profile_edit_cancel">Cancel</string>
     <string name="profile_name_label">Profile Name:</string>
-    <string name="profile_name_hint">(use gateway address)</string>
-    <string name="profile_gateway_label">Gateway:</string>
+    <string name="profile_name_hint">(use server address)</string>
+    <string name="profile_gateway_label">Server:</string>
     <string name="profile_vpn_type_label">Type:</string>
     <string name="profile_username_label">Username:</string>
     <string name="profile_password_label">Password:</string>
     <string name="profile_split_tunnelingv4_title">Block IPv4 traffic not destined for the VPN</string>
     <string name="profile_split_tunnelingv6_title">Block IPv6 traffic not destined for the VPN</string>
     <!-- Warnings/Notifications in the details view -->
-    <string name="alert_text_no_input_gateway">Please enter the gateway address here</string>
+    <string name="alert_text_no_input_gateway">Please enter the server address here</string>
     <string name="alert_text_no_input_username">Please enter your username here</string>
     <string name="alert_text_nocertfound_title">No CA certificate selected</string>
     <string name="alert_text_nocertfound">Please select one or activate <i>Select automatically</i></string>
     <string name="alert_text_out_of_range">Please enter a number in the range from %1$d - %2$d</string>
     <string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
-    <string name="tnc_notice_subtitle">Device data is sent to the gateway operator</string>
-    <string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows gateway operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the gateway operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the gateway\'s identity.&lt;/b></string>
+    <string name="tnc_notice_subtitle">Device data is sent to the server operator</string>
+    <string name="tnc_notice_details"><![CDATA[<p>Trusted Network Connect (TNC) allows server operators to assess the health of a client device.</p><p>For that purpose the server operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.</p><b>Any data will be sent only after verifying the server\'s identity.</b>]]></string>
 
     <!-- Trusted certificate selection -->
     <string name="trusted_certs_title">CA certificates</string>
     <string name="login_title">Enter password to connect</string>
     <string name="login_confirm">Connect</string>
     <string name="error_introduction">Failed to establish VPN:</string>
-    <string name="error_lookup_failed">Gateway address lookup failed.</string>
-    <string name="error_unreachable">Gateway is unreachable.</string>
-    <string name="error_peer_auth_failed">Verifying gateway authentication failed.</string>
+    <string name="error_lookup_failed">Server address lookup failed.</string>
+    <string name="error_unreachable">Server is unreachable.</string>
+    <string name="error_peer_auth_failed">Verifying server authentication failed.</string>
     <string name="error_auth_failed">User authentication failed.</string>
     <string name="error_assessment_failed">Security assessment failed.</string>
     <string name="error_generic">Unspecified failure while connecting.</string>
index 739ba70..82a9578 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-    Copyright (C) 2012 Tobias Brunner
-    Hochschule fuer Technik Rapperswil
+    Copyright (C) 2012-2016 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
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="ApplicationTheme" parent="@android:style/Theme.Holo">
+    <style name="ApplicationTheme.Base" parent="Theme.AppCompat">
+        <item name="colorAccent">@color/accent</item>
+        <item name="colorPrimary">@color/primary</item>
+        <item name="colorPrimaryDark">@color/primary_dark</item>
+        <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
+    </style>
+
+    <style name="AlertDialogTheme.Base" parent="Theme.AppCompat.Dialog.Alert">
+        <item name="colorAccent">@color/accent</item>
     </style>
 
 </resources>
index 9b18c6e..81d32a8 100644 (file)
@@ -3,7 +3,7 @@ buildscript {
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:1.3.0'
+        classpath 'com.android.tools.build:gradle:2.1.0'
     }
 }
 
index 0c71e76..3389226 100644 (file)
@@ -1,6 +1,6 @@
-#Wed Apr 10 15:27:10 PDT 2013
+#Wed Apr 13 11:22:32 CEST 2016
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip