Merge branch 'android-tabs'

This migrates some deprecated Android APIs to replacements provided by
the support library.  This also changes the theme slightly.
This commit is contained in:
Tobias Brunner
2016-04-27 14:38:08 +02:00
36 changed files with 579 additions and 398 deletions
+1
View File
@@ -1,5 +1,6 @@
.gradle/ .gradle/
.idea/ .idea/
build/
app/build/ app/build/
app/src/main/libs app/src/main/libs
app/src/main/obj app/src/main/obj
+5 -2
View File
@@ -1,8 +1,8 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 21 compileSdkVersion 23
buildToolsVersion "22.0.1" buildToolsVersion "23.0.3"
defaultConfig { defaultConfig {
applicationId "org.strongswan.android" applicationId "org.strongswan.android"
@@ -29,6 +29,7 @@ android {
tasks.withType(JavaCompile) { tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn buildNative compileTask -> compileTask.dependsOn buildNative
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
} }
clean.dependsOn 'cleanNative' clean.dependsOn 'cleanNative'
@@ -42,5 +43,7 @@ android {
} }
dependencies { dependencies {
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:design:23.3.0'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
} }
@@ -66,7 +66,7 @@
<activity <activity
android:name=".ui.TrustedCertificateImportActivity" android:name=".ui.TrustedCertificateImportActivity"
android:label="@string/import_certificate" android:label="@string/import_certificate"
android:theme="@android:style/Theme.Holo.Dialog.NoActionBar" > android:theme="@style/AlertDialogTheme" >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2012-2014 Tobias Brunner * Copyright (C) 2012-2015 Tobias Brunner
* Copyright (C) 2012 Giuliano Grassi * Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager * Copyright (C) 2012 Ralf Sager
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
@@ -17,6 +17,8 @@
package org.strongswan.android.logic; package org.strongswan.android.logic;
import android.util.Log;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreException; import java.security.KeyStoreException;
import java.security.cert.Certificate; import java.security.cert.Certificate;
@@ -24,11 +26,10 @@ import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Observable;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import android.util.Log; public class TrustedCertificateManager extends Observable
public class TrustedCertificateManager
{ {
private static final String TAG = TrustedCertificateManager.class.getSimpleName(); private static final String TAG = TrustedCertificateManager.class.getSimpleName();
private final ReentrantReadWriteLock mLock = new ReentrantReadWriteLock(); private final ReentrantReadWriteLock mLock = new ReentrantReadWriteLock();
@@ -61,13 +62,13 @@ public class TrustedCertificateManager
*/ */
private TrustedCertificateManager() private TrustedCertificateManager()
{ {
for (String name : new String[] { "LocalCertificateStore", "AndroidCAStore" }) for (String name : new String[]{"LocalCertificateStore", "AndroidCAStore"})
{ {
KeyStore store; KeyStore store;
try try
{ {
store = KeyStore.getInstance(name); store = KeyStore.getInstance(name);
store.load(null,null); store.load(null, null);
mKeyStores.add(store); mKeyStores.add(store);
} }
catch (Exception e) catch (Exception e)
@@ -81,12 +82,14 @@ public class TrustedCertificateManager
/** /**
* This is not instantiated until the first call to getInstance() * 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(); public static final TrustedCertificateManager mInstance = new TrustedCertificateManager();
} }
/** /**
* Get the single instance of the CA certificate manager. * Get the single instance of the CA certificate manager.
*
* @return CA certificate manager * @return CA certificate manager
*/ */
public static TrustedCertificateManager getInstance() public static TrustedCertificateManager getInstance()
@@ -97,12 +100,17 @@ public class TrustedCertificateManager
/** /**
* Invalidates the current load state so that the next call to load() * Invalidates the current load state so that the next call to load()
* will force a reload of the cached CA certificates. * will force a reload of the cached CA certificates.
*
* Observers are notified when this method is called.
*
* @return reference to itself * @return reference to itself
*/ */
public TrustedCertificateManager reset() public TrustedCertificateManager reset()
{ {
Log.d(TAG, "Force reload of cached CA certificates on next load"); Log.d(TAG, "Force reload of cached CA certificates on next load");
this.mReload = true; this.mReload = true;
this.setChanged();
this.notifyObservers();
return this; return this;
} }
@@ -110,6 +118,9 @@ public class TrustedCertificateManager
* Ensures that the certificates are loaded but does not force a reload. * 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 * As this takes a while if the certificates are not loaded yet it should
* be called asynchronously. * be called asynchronously.
*
* Observers are only notified when the certificates are initially loaded, not when reloaded.
*
* @return reference to itself * @return reference to itself
*/ */
public TrustedCertificateManager load() public TrustedCertificateManager load()
@@ -138,12 +149,18 @@ public class TrustedCertificateManager
fetchCertificates(certs, store); fetchCertificates(certs, store);
} }
this.mCACerts = certs; this.mCACerts = certs;
this.mLoaded = true; if (!this.mLoaded)
{
this.setChanged();
this.notifyObservers();
this.mLoaded = true;
}
Log.d(TAG, "Cached CA certificates loaded"); Log.d(TAG, "Cached CA certificates loaded");
} }
/** /**
* Load all X.509 certificates from the given KeyStore. * Load all X.509 certificates from the given KeyStore.
*
* @param certs Hashtable to store certificates in * @param certs Hashtable to store certificates in
* @param store KeyStore to load certificates from * @param store KeyStore to load certificates from
*/ */
@@ -171,6 +188,7 @@ public class TrustedCertificateManager
/** /**
* Retrieve the CA certificate with the given alias. * Retrieve the CA certificate with the given alias.
*
* @param alias alias of the certificate to get * @param alias alias of the certificate to get
* @return the certificate, null if not found * @return the certificate, null if not found
*/ */
@@ -208,6 +226,7 @@ public class TrustedCertificateManager
/** /**
* Get all CA certificates (from all keystores). * Get all CA certificates (from all keystores).
*
* @return Hashtable mapping aliases to certificates * @return Hashtable mapping aliases to certificates
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -222,6 +241,7 @@ public class TrustedCertificateManager
/** /**
* Get all certificates from the given source. * Get all certificates from the given source.
*
* @param source type to filter certificates * @param source type to filter certificates
* @return Hashtable mapping aliases to certificates * @return Hashtable mapping aliases to certificates
*/ */
@@ -15,20 +15,20 @@
package org.strongswan.android.ui; package org.strongswan.android.ui;
import org.strongswan.android.R;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; 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 * Class that displays a confirmation dialog to delete a selected local
* certificate. * certificate.
*/ */
public class CertificateDeleteConfirmationDialog extends DialogFragment public class CertificateDeleteConfirmationDialog extends AppCompatDialogFragment
{ {
public static final String ALIAS = "alias"; public static final String ALIAS = "alias";
OnCertificateDeleteListener mListener; OnCertificateDeleteListener mListener;
@@ -15,14 +15,6 @@
package org.strongswan.android.ui; 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.Fragment;
import android.app.FragmentManager; import android.app.FragmentManager;
import android.app.FragmentTransaction; import android.app.FragmentTransaction;
@@ -33,6 +25,7 @@ import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.support.v4.content.ContextCompat;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
@@ -44,13 +37,24 @@ import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; 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 public class ImcStateFragment extends Fragment implements VpnStateListener
{ {
private int mColorIsolate;
private int mColorBlock;
private TextView mStateView; private TextView mStateView;
private TextView mAction; private TextView mAction;
private LinearLayout mButton; private LinearLayout mButton;
private VpnStateService mService; private VpnStateService mService;
private final ServiceConnection mServiceConnection = new ServiceConnection() { private final ServiceConnection mServiceConnection = new ServiceConnection()
{
@Override @Override
public void onServiceDisconnected(ComponentName name) public void onServiceDisconnected(ComponentName name)
{ {
@@ -71,6 +75,9 @@ public class ImcStateFragment extends Fragment implements VpnStateListener
{ {
super.onCreate(savedInstanceState); 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 */ /* bind to the service only seems to work from the ApplicationContext */
Context context = getActivity().getApplicationContext(); Context context = getActivity().getApplicationContext();
context.bindService(new Intent(context, VpnStateService.class), 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); View view = inflater.inflate(R.layout.imc_state_fragment, container, false);
mButton = (LinearLayout)view.findViewById(R.id.imc_state_button); mButton = (LinearLayout)view.findViewById(R.id.imc_state_button);
mButton.setOnClickListener(new OnClickListener() { mButton.setOnClickListener(new OnClickListener()
{
@Override @Override
public void onClick(View v) public void onClick(View v)
{ {
@@ -104,7 +112,8 @@ public class ImcStateFragment extends Fragment implements VpnStateListener
startActivity(intent); 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 */ /* a better value would be getScaledTouchExplorationTapSlop() but that is hidden */
private final int mMinDistance = ViewConfiguration.get(getActivity()).getScaledTouchSlop() * 4; private final int mMinDistance = ViewConfiguration.get(getActivity()).getScaledTouchSlop() * 4;
@@ -122,7 +131,8 @@ public class ImcStateFragment extends Fragment implements VpnStateListener
return false; return false;
} }
}); });
mButton.setOnTouchListener(new OnTouchListener() { mButton.setOnTouchListener(new OnTouchListener()
{
@Override @Override
public boolean onTouch(View v, MotionEvent event) public boolean onTouch(View v, MotionEvent event)
{ {
@@ -190,12 +200,12 @@ public class ImcStateFragment extends Fragment implements VpnStateListener
break; break;
case ISOLATE: case ISOLATE:
mStateView.setText(R.string.imc_state_isolate); mStateView.setText(R.string.imc_state_isolate);
mStateView.setTextColor(getResources().getColor(R.color.warning_text)); mStateView.setTextColor(mColorIsolate);
ft.show(this); ft.show(this);
break; break;
case BLOCK: case BLOCK:
mStateView.setText(R.string.imc_state_block); mStateView.setText(R.string.imc_state_block);
mStateView.setTextColor(getResources().getColor(R.color.error_text)); mStateView.setTextColor(mColorBlock);
ft.show(this); ft.show(this);
break; break;
} }
@@ -15,21 +15,21 @@
package org.strongswan.android.ui; package org.strongswan.android.ui;
import java.io.File; 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;
import org.strongswan.android.R; import org.strongswan.android.R;
import org.strongswan.android.data.LogContentProvider; import org.strongswan.android.data.LogContentProvider;
import org.strongswan.android.logic.CharonVpnService; import org.strongswan.android.logic.CharonVpnService;
import android.app.Activity; import java.io.File;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class LogActivity extends Activity public class LogActivity extends AppCompatActivity
{ {
@Override @Override
public void onCreate(Bundle savedInstanceState) public void onCreate(Bundle savedInstanceState)
@@ -37,7 +37,7 @@ public class LogActivity extends Activity
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.log_activity); setContentView(R.layout.log_activity);
getActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} }
@Override @Override
@@ -74,7 +74,7 @@ public class LogActivity extends Activity
} }
Intent intent = new Intent(Intent.ACTION_SEND); 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.putExtra(Intent.EXTRA_SUBJECT, String.format(getString(R.string.log_mail_subject), version));
intent.setType("text/plain"); intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_STREAM, LogContentProvider.createContentUri()); intent.putExtra(Intent.EXTRA_STREAM, LogContentProvider.createContentUri());
@@ -17,22 +17,7 @@
package org.strongswan.android.ui; 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.Dialog;
import android.app.DialogFragment;
import android.app.Fragment; import android.app.Fragment;
import android.app.FragmentManager; import android.app.FragmentManager;
import android.app.FragmentTransaction; import android.app.FragmentTransaction;
@@ -46,6 +31,10 @@ import android.net.VpnService;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; 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.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
@@ -54,12 +43,24 @@ import android.view.Window;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Toast; 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 = "[email protected]"; public static final String CONTACT_EMAIL = "[email protected]";
public static final String START_PROFILE = "org.strongswan.android.action.START_PROFILE"; 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"; 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; public static final boolean USE_BYOD = true;
private static final int PREPARE_VPN_SERVICE = 0; private static final int PREPARE_VPN_SERVICE = 0;
private static final String PROFILE_NAME = "org.strongswan.android.MainActivity.PROFILE_NAME"; 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 Bundle mProfileInfo;
private VpnStateService mService; private VpnStateService mService;
private final ServiceConnection mServiceConnection = new ServiceConnection() { private final ServiceConnection mServiceConnection = new ServiceConnection()
{
@Override @Override
public void onServiceDisconnected(ComponentName name) public void onServiceDisconnected(ComponentName name)
{ {
@@ -91,16 +93,18 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
@Override @Override
public void onCreate(Bundle savedInstanceState) public void onCreate(Bundle savedInstanceState)
{ {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
super.onCreate(savedInstanceState);
setContentView(R.layout.main); 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), this.bindService(new Intent(this, VpnStateService.class),
mServiceConnection, Service.BIND_AUTO_CREATE); mServiceConnection, Service.BIND_AUTO_CREATE);
ActionBar bar = getActionBar();
bar.setDisplayShowTitleEnabled(false);
/* load CA certificates in a background task */ /* load CA certificates in a background task */
new LoadCertificatesTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 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 * Prepare the VpnService. If this succeeds the current VPN profile is
* started. * started.
*
* @param profileInfo a bundle containing the information about the profile to be started * @param profileInfo a bundle containing the information about the profile to be started
*/ */
protected void prepareVpnService(Bundle profileInfo) protected void prepareVpnService(Bundle profileInfo)
@@ -231,7 +236,7 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
ConfirmationDialog dialog = new ConfirmationDialog(); ConfirmationDialog dialog = new ConfirmationDialog();
dialog.setArguments(profileInfo); dialog.setArguments(profileInfo);
dialog.show(this.getFragmentManager(), DIALOG_TAG); dialog.show(this.getSupportFragmentManager(), DIALOG_TAG);
return; return;
} }
startVpnProfile(profileInfo); 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. * Start the given VPN profile asking the user for a password if required.
*
* @param profileInfo data about the profile * @param profileInfo data about the profile
*/ */
private void startVpnProfile(Bundle profileInfo) private void startVpnProfile(Bundle profileInfo)
@@ -248,7 +254,7 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
{ {
LoginDialog login = new LoginDialog(); LoginDialog login = new LoginDialog();
login.setArguments(profileInfo); login.setArguments(profileInfo);
login.show(getFragmentManager(), DIALOG_TAG); login.show(getSupportFragmentManager(), DIALOG_TAG);
return; return;
} }
prepareVpnService(profileInfo); 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 * Start the VPN profile referred to by the given intent. Displays an error
* if the profile doesn't exist. * if the profile doesn't exist.
*
* @param intent Intent that caused us to start this * @param intent Intent that caused us to start this
*/ */
private void startVpnProfile(Intent intent) private void startVpnProfile(Intent intent)
@@ -291,11 +298,13 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
{ {
setProgressBarIndeterminateVisibility(true); setProgressBarIndeterminateVisibility(true);
} }
@Override @Override
protected TrustedCertificateManager doInBackground(Void... params) protected TrustedCertificateManager doInBackground(Void... params)
{ {
return TrustedCertificateManager.getInstance().load(); return TrustedCertificateManager.getInstance().load();
} }
@Override @Override
protected void onPostExecute(TrustedCertificateManager result) 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 * 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. * 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 @Override
public Dialog onCreateDialog(Bundle savedInstanceState) public Dialog onCreateDialog(Bundle savedInstanceState)
@@ -345,7 +354,8 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
.setIcon(icon) .setIcon(icon)
.setTitle(String.format(getString(title), profileInfo.getString(PROFILE_NAME))) .setTitle(String.format(getString(title), profileInfo.getString(PROFILE_NAME)))
.setMessage(message) .setMessage(message)
.setPositiveButton(button, new DialogInterface.OnClickListener() { .setPositiveButton(button, new DialogInterface.OnClickListener()
{
@Override @Override
public void onClick(DialogInterface dialog, int whichButton) public void onClick(DialogInterface dialog, int whichButton)
{ {
@@ -353,7 +363,8 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
activity.startVpnProfile(profileInfo); activity.startVpnProfile(profileInfo);
} }
}) })
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
{
@Override @Override
public void onClick(DialogInterface dialog, int which) 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 * Class that displays a login dialog and initiates the selected VPN
* profile if the user confirms the dialog. * profile if the user confirms the dialog.
*/ */
public static class LoginDialog extends DialogFragment public static class LoginDialog extends AppCompatDialogFragment
{ {
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) public Dialog onCreateDialog(Bundle savedInstanceState)
@@ -379,10 +390,11 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
username.setText(profileInfo.getString(VpnProfileDataSource.KEY_USERNAME)); username.setText(profileInfo.getString(VpnProfileDataSource.KEY_USERNAME));
final EditText password = (EditText)view.findViewById(R.id.password); 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.setView(view);
adb.setTitle(getString(R.string.login_title)); 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 @Override
public void onClick(DialogInterface dialog, int whichButton) public void onClick(DialogInterface dialog, int whichButton)
{ {
@@ -391,7 +403,8 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
activity.prepareVpnService(profileInfo); activity.prepareVpnService(profileInfo);
} }
}); });
adb.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { adb.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
{
@Override @Override
public void onClick(DialogInterface dialog, int which) 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 * Class representing an error message which is displayed if VpnService is
* not supported on the current device. * 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"; 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 bundle = new Bundle();
bundle.putInt(ERROR_MESSAGE_ID, messageId); bundle.putInt(ERROR_MESSAGE_ID, messageId);
VpnNotSupportedError dialog = new VpnNotSupportedError(); VpnNotSupportedError dialog = new VpnNotSupportedError();
dialog.setArguments(bundle); dialog.setArguments(bundle);
dialog.show(activity.getFragmentManager(), DIALOG_TAG); dialog.show(activity.getSupportFragmentManager(), DIALOG_TAG);
} }
@Override @Override
@@ -428,7 +441,8 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
.setTitle(R.string.vpn_not_supported_title) .setTitle(R.string.vpn_not_supported_title)
.setMessage(messageId) .setMessage(messageId)
.setCancelable(false) .setCancelable(false)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
{
@Override @Override
public void onClick(DialogInterface dialog, int id) public void onClick(DialogInterface dialog, int id)
{ {
@@ -15,24 +15,24 @@
package org.strongswan.android.ui; 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.R;
import org.strongswan.android.logic.imc.RemediationInstruction; import org.strongswan.android.logic.imc.RemediationInstruction;
import org.strongswan.android.ui.RemediationInstructionsFragment.OnRemediationInstructionSelectedListener; import org.strongswan.android.ui.RemediationInstructionsFragment.OnRemediationInstructionSelectedListener;
import android.app.Activity; import java.util.ArrayList;
import android.os.Bundle;
import android.view.MenuItem;
public class RemediationInstructionsActivity extends Activity implements OnRemediationInstructionSelectedListener public class RemediationInstructionsActivity extends AppCompatActivity implements OnRemediationInstructionSelectedListener
{ {
@Override @Override
protected void onCreate(Bundle savedInstanceState) protected void onCreate(Bundle savedInstanceState)
{ {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.remediation_instructions); setContentView(R.layout.remediation_instructions);
getActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
if (savedInstanceState != null) if (savedInstanceState != null)
{ /* only update if we're not restoring */ { /* only update if we're not restoring */
@@ -64,7 +64,7 @@ public class RemediationInstructionsActivity extends Activity implements OnRemed
{ {
finish(); finish();
} }
getActionBar().setTitle(getTitle()); getSupportActionBar().setTitle(getTitle());
return true; return true;
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
@@ -88,7 +88,7 @@ public class RemediationInstructionsActivity extends Activity implements OnRemed
frag.setArguments(args); frag.setArguments(args);
getFragmentManager().beginTransaction().replace(R.id.fragment_container, frag).addToBackStack(null).commit(); getFragmentManager().beginTransaction().replace(R.id.fragment_container, frag).addToBackStack(null).commit();
getActionBar().setTitle(instruction.getTitle()); getSupportActionBar().setTitle(instruction.getTitle());
} }
} }
} }
@@ -15,6 +15,24 @@
package org.strongswan.android.ui; package org.strongswan.android.ui;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Dialog;
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;
import org.strongswan.android.R;
import org.strongswan.android.data.VpnProfileDataSource;
import org.strongswan.android.logic.TrustedCertificateManager;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.InputStream; import java.io.InputStream;
import java.security.KeyStore; import java.security.KeyStore;
@@ -22,34 +40,17 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import org.strongswan.android.R; public class TrustedCertificateImportActivity extends AppCompatActivity
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.widget.Toast;
public class TrustedCertificateImportActivity extends Activity
{ {
private static final int OPEN_DOCUMENT = 0; private static final int OPEN_DOCUMENT = 0;
private static final String DIALOG_TAG = "Dialog"; private static final String DIALOG_TAG = "Dialog";
/* same as those listed in the manifest */ /* same as those listed in the manifest */
private static final String[] ACCEPTED_MIME_TYPES = { private static final String[] ACCEPTED_MIME_TYPES = {
"application/x-x509-ca-cert", "application/x-x509-ca-cert",
"application/x-x509-server-cert", "application/x-x509-server-cert",
"application/x-pem-file", "application/x-pem-file",
"application/pkix-cert" "application/pkix-cert"
}; };
@TargetApi(Build.VERSION_CODES.KITKAT) @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. * Import the file pointed to by the given URI as a certificate.
*
* @param uri * @param uri
*/ */
private void importCertificate(Uri uri) private void importCertificate(Uri uri)
@@ -117,13 +119,14 @@ public class TrustedCertificateImportActivity extends Activity
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putSerializable(VpnProfileDataSource.KEY_CERTIFICATE, certificate); args.putSerializable(VpnProfileDataSource.KEY_CERTIFICATE, certificate);
dialog.setArguments(args); dialog.setArguments(args);
FragmentTransaction ft = getFragmentManager().beginTransaction(); FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(dialog, DIALOG_TAG); ft.add(dialog, DIALOG_TAG);
ft.commit(); ft.commit();
} }
/** /**
* Load the file from the given URI and try to parse it as X.509 certificate. * Load the file from the given URI and try to parse it as X.509 certificate.
*
* @param uri * @param uri
* @return certificate or null * @return certificate or null
*/ */
@@ -151,6 +154,7 @@ public class TrustedCertificateImportActivity extends Activity
/** /**
* Try to store the given certificate in the KeyStore. * Try to store the given certificate in the KeyStore.
*
* @param certificate * @param certificate
* @return whether it was successfully stored * @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 * Class that displays a confirmation dialog when a certificate should get
* imported. If the user confirms the import we try to store it. * 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 @Override
public Dialog onCreateDialog(Bundle savedInstanceState) public Dialog onCreateDialog(Bundle savedInstanceState)
@@ -188,7 +192,8 @@ public class TrustedCertificateImportActivity extends Activity
.setIcon(R.drawable.ic_launcher) .setIcon(R.drawable.ic_launcher)
.setTitle(R.string.import_certificate) .setTitle(R.string.import_certificate)
.setMessage(certificate.getSubjectDN().toString()) .setMessage(certificate.getSubjectDN().toString())
.setPositiveButton(R.string.import_certificate, new DialogInterface.OnClickListener() { .setPositiveButton(R.string.import_certificate, new DialogInterface.OnClickListener()
{
@Override @Override
public void onClick(DialogInterface dialog, int whichButton) public void onClick(DialogInterface dialog, int whichButton)
{ {
@@ -205,7 +210,8 @@ public class TrustedCertificateImportActivity extends Activity
getActivity().finish(); getActivity().finish();
} }
}) })
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
{
@Override @Override
public void onClick(DialogInterface dialog, int which) public void onClick(DialogInterface dialog, int which)
{ {
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2012-2014 Tobias Brunner * Copyright (C) 2012-2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@@ -15,26 +15,12 @@
package org.strongswan.android.ui; 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.Context;
import android.content.Loader;
import android.os.Bundle; 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.text.TextUtils;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@@ -44,6 +30,21 @@ import android.widget.ListView;
import android.widget.SearchView; import android.widget.SearchView;
import android.widget.SearchView.OnQueryTextListener; 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 class TrustedCertificateListFragment extends ListFragment implements LoaderCallbacks<List<TrustedCertificateEntry>>, OnQueryTextListener
{ {
public static final String EXTRA_CERTIFICATE_SOURCE = "certificate_source"; 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 * The activity containing this fragment should implement this interface
*/ */
public interface OnTrustedCertificateSelectedListener { public interface OnTrustedCertificateSelectedListener
{
public void onTrustedCertificateSelected(TrustedCertificateEntry selected); public void onTrustedCertificateSelected(TrustedCertificateEntry selected);
} }
@@ -87,13 +89,13 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
} }
@Override @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; return true;
} }
/**
* Reset the loader of this list fragment
*/
public void reset()
{
if (isResumed())
{
setListShown(false);
}
getLoaderManager().restartLoader(0, null, this);
}
@Override @Override
public Loader<List<TrustedCertificateEntry>> onCreateLoader(int id, Bundle args) public Loader<List<TrustedCertificateEntry>> onCreateLoader(int id, Bundle args)
{ /* we don't need the id as we have only one loader */ { /* 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 List<TrustedCertificateEntry> mData;
private final TrustedCertificateSource mSource; private final TrustedCertificateSource mSource;
private TrustedCertificateManagerObserver mObserver;
public CertificateListLoader(Context context, TrustedCertificateSource source) public CertificateListLoader(Context context, TrustedCertificateSource source)
{ {
@@ -186,7 +177,7 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
public List<TrustedCertificateEntry> loadInBackground() public List<TrustedCertificateEntry> loadInBackground()
{ {
TrustedCertificateManager certman = TrustedCertificateManager.getInstance().load(); TrustedCertificateManager certman = TrustedCertificateManager.getInstance().load();
Hashtable<String,X509Certificate> certificates = certman.getCACertificates(mSource); Hashtable<String, X509Certificate> certificates = certman.getCACertificates(mSource);
List<TrustedCertificateEntry> selected; List<TrustedCertificateEntry> selected;
selected = new ArrayList<TrustedCertificateEntry>(); selected = new ArrayList<TrustedCertificateEntry>();
@@ -204,9 +195,11 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
if (mData != null) if (mData != null)
{ /* if we have data ready, deliver it directly */ { /* if we have data ready, deliver it directly */
deliverResult(mData); deliverResult(mData);
return;
} }
forceLoad(); if (takeContentChanged() || mData == null)
{
forceLoad();
}
} }
@Override @Override
@@ -220,6 +213,11 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
if (isStarted()) if (isStarted())
{ /* if it is started we deliver the data directly, { /* if it is started we deliver the data directly,
* otherwise this is handled in onStartLoading */ * otherwise this is handled in onStartLoading */
if (mObserver == null)
{
mObserver = new TrustedCertificateManagerObserver();
TrustedCertificateManager.getInstance().addObserver(mObserver);
}
super.deliverResult(data); super.deliverResult(data);
} }
} }
@@ -227,7 +225,34 @@ public class TrustedCertificateListFragment extends ListFragment implements Load
@Override @Override
protected void onReset() protected void onReset()
{ {
if (mObserver != null)
{
TrustedCertificateManager.getInstance().deleteObserver(mObserver);
mObserver = null;
}
mData = 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);
}
} }
} }
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2012-2014 Tobias Brunner * Copyright (C) 2012-2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@@ -15,7 +15,20 @@
package org.strongswan.android.ui; 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.R;
import org.strongswan.android.data.VpnProfileDataSource; 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.security.TrustedCertificateEntry;
import org.strongswan.android.ui.CertificateDeleteConfirmationDialog.OnCertificateDeleteListener; import org.strongswan.android.ui.CertificateDeleteConfirmationDialog.OnCertificateDeleteListener;
import android.app.ActionBar; import java.security.KeyStore;
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;
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"; public static final String SELECT_CERTIFICATE = "org.strongswan.android.action.SELECT_CERTIFICATE";
private static final String DIALOG_TAG = "Dialog"; private static final String DIALOG_TAG = "Dialog";
private static final int IMPORT_CERTIFICATE = 0; private static final int IMPORT_CERTIFICATE = 0;
private TrustedCertificatesPagerAdapter mAdapter;
private ViewPager mPager;
private boolean mSelect; private boolean mSelect;
@Override @Override
@@ -48,44 +54,20 @@ public class TrustedCertificatesActivity extends Activity implements TrustedCert
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.trusted_certificates_activity); setContentView(R.layout.trusted_certificates_activity);
ActionBar actionBar = getActionBar(); ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
TrustedCertificatesTabListener listener; mAdapter = new TrustedCertificatesPagerAdapter(getSupportFragmentManager(), this);
listener = new TrustedCertificatesTabListener(this, "system", TrustedCertificateSource.SYSTEM);
actionBar.addTab(actionBar mPager = (ViewPager)findViewById(R.id.viewpager);
.newTab() mPager.setAdapter(mAdapter);
.setText(R.string.system_tab)
.setTag(listener) TabLayout tabs = (TabLayout)findViewById(R.id.tabs);
.setTabListener(listener)); tabs.setupWithViewPager(mPager);
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()); mSelect = SELECT_CERTIFICATE.equals(getIntent().getAction());
} }
@Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) public boolean onCreateOptionsMenu(Menu menu)
{ {
@@ -148,18 +130,13 @@ public class TrustedCertificatesActivity extends Activity implements TrustedCert
setResult(Activity.RESULT_OK, intent); setResult(Activity.RESULT_OK, intent);
finish(); finish();
} }
else else if (mAdapter.getSource(mPager.getCurrentItem()) == TrustedCertificateSource.LOCAL)
{ {
TrustedCertificatesTabListener listener; Bundle args = new Bundle();
listener = (TrustedCertificatesTabListener)getActionBar().getSelectedTab().getTag(); args.putString(CertificateDeleteConfirmationDialog.ALIAS, selected.getAlias());
if (listener.mTag == "local") CertificateDeleteConfirmationDialog dialog = new CertificateDeleteConfirmationDialog();
{ dialog.setArguments(args);
Bundle args = new Bundle(); dialog.show(getSupportFragmentManager(), DIALOG_TAG);
args.putString(CertificateDeleteConfirmationDialog.ALIAS, selected.getAlias());
CertificateDeleteConfirmationDialog dialog = new CertificateDeleteConfirmationDialog();
dialog.setArguments(args);
dialog.show(this.getFragmentManager(), DIALOG_TAG);
}
} }
} }
@@ -182,74 +159,69 @@ public class TrustedCertificatesActivity extends Activity implements TrustedCert
private void reloadCertificates() private void reloadCertificates()
{ {
TrustedCertificateManager.getInstance().reset(); TrustedCertificateManager.getInstance().reset();
for (int i = 0; i < getActionBar().getTabCount(); i++) }
public static class TrustedCertificatesPagerAdapter extends FragmentPagerAdapter
{
private TrustedCertificatesTab mTabs[];
public TrustedCertificatesPagerAdapter(FragmentManager fm, Context context)
{ {
Tab tab = getActionBar().getTabAt(i); super(fm);
TrustedCertificatesTabListener listener = (TrustedCertificatesTabListener)tab.getTag(); mTabs = new TrustedCertificatesTab[]{
listener.reset(); 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 int getCount()
{
return mTabs.length;
}
@Override
public CharSequence getPageTitle(int position)
{
return mTabs[position].getTitle();
}
public TrustedCertificateSource getSource(int position)
{
return mTabs[position].getSource();
}
@Override
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 TrustedCertificatesTabListener implements ActionBar.TabListener public static class TrustedCertificatesTab
{ {
private final String mTag; private final String mTitle;
private final TrustedCertificateSource mSource; private final TrustedCertificateSource mSource;
private Fragment mFragment;
public TrustedCertificatesTabListener(Activity activity, String tag, TrustedCertificateSource source) public TrustedCertificatesTab(String title, TrustedCertificateSource source)
{ {
mTag = tag; mTitle = title;
mSource = source; 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();
}
} }
@Override public String getTitle()
public void onTabSelected(Tab tab, FragmentTransaction ft)
{ {
if (mFragment == null) return mTitle;
{
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);
}
} }
@Override public TrustedCertificateSource getSource()
public void onTabUnselected(Tab tab, FragmentTransaction ft)
{ {
if (mFragment != null) return mSource;
{
ft.detach(mFragment);
}
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft)
{
/* nothing to be done */
}
public void reset()
{
if (mFragment != null)
{
((TrustedCertificateListFragment)mFragment).reset();
}
} }
} }
} }
@@ -17,20 +17,7 @@
package org.strongswan.android.ui; 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.Dialog;
import android.app.DialogFragment;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
@@ -39,6 +26,9 @@ import android.os.Bundle;
import android.security.KeyChain; import android.security.KeyChain;
import android.security.KeyChainAliasCallback; import android.security.KeyChainAliasCallback;
import android.security.KeyChainException; 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.text.Html;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
@@ -57,7 +47,17 @@ import android.widget.RelativeLayout;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; 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 SELECT_TRUSTED_CERTIFICATE = 0;
private static final int MTU_MIN = 1280; private static final int MTU_MIN = 1280;
@@ -94,7 +94,7 @@ public class VpnProfileDetailActivity extends Activity
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
/* the title is set when we load the profile, if any */ /* the title is set when we load the profile, if any */
getActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mDataSource = new VpnProfileDataSource(this); mDataSource = new VpnProfileDataSource(this);
mDataSource.open(); mDataSource.open();
@@ -146,7 +146,7 @@ public class VpnProfileDetailActivity extends Activity
@Override @Override
public void onClick(View v) 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; String useralias = null, alias = null;
getActionBar().setTitle(R.string.add_profile); getSupportActionBar().setTitle(R.string.add_profile);
if (mId != null && mId != 0) if (mId != null && mId != 0)
{ {
mProfile = mDataSource.getVpnProfile(mId); 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); mBlockIPv6.setChecked(mProfile.getSplitTunneling() != null ? (mProfile.getSplitTunneling() & VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6) != 0 : false);
useralias = mProfile.getUserCertificateAlias(); useralias = mProfile.getUserCertificateAlias();
alias = mProfile.getCertificateAlias(); alias = mProfile.getCertificateAlias();
getActionBar().setTitle(mProfile.getName()); getSupportActionBar().setTitle(mProfile.getName());
} }
else else
{ {
@@ -633,7 +633,7 @@ public class VpnProfileDetailActivity extends Activity
/** /**
* Dialog with notification message if EAP-TNC is used. * Dialog with notification message if EAP-TNC is used.
*/ */
public static class TncNoticeDialog extends DialogFragment public static class TncNoticeDialog extends AppCompatDialogFragment
{ {
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) public Dialog onCreateDialog(Bundle savedInstanceState)
@@ -109,15 +109,13 @@ public class VpnProfileListFragment extends Fragment
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
Context context = getActivity().getApplicationContext();
mDataSource = new VpnProfileDataSource(this.getActivity()); mDataSource = new VpnProfileDataSource(this.getActivity());
mDataSource.open(); mDataSource.open();
/* cached list of profiles used as backend for the ListView */ /* cached list of profiles used as backend for the ListView */
mVpnProfiles = mDataSource.getAllVpnProfiles(); mVpnProfiles = mDataSource.getAllVpnProfiles();
mListAdapter = new VpnProfileAdapter(context, R.layout.profile_list_item, mVpnProfiles); mListAdapter = new VpnProfileAdapter(getActivity(), R.layout.profile_list_item, mVpnProfiles);
} }
@Override @Override
@@ -15,15 +15,15 @@
package org.strongswan.android.ui; 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.R;
import org.strongswan.android.data.VpnProfile; import org.strongswan.android.data.VpnProfile;
import org.strongswan.android.ui.VpnProfileListFragment.OnVpnProfileSelectedListener; import org.strongswan.android.ui.VpnProfileListFragment.OnVpnProfileSelectedListener;
import android.app.Activity; public class VpnProfileSelectActivity extends AppCompatActivity implements OnVpnProfileSelectedListener
import android.content.Intent;
import android.os.Bundle;
public class VpnProfileSelectActivity extends Activity implements OnVpnProfileSelectedListener
{ {
@Override @Override
protected void onCreate(Bundle savedInstanceState) protected void onCreate(Bundle savedInstanceState)
@@ -17,19 +17,6 @@
package org.strongswan.android.ui; 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.Fragment;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.app.Service; import android.app.Service;
@@ -40,6 +27,8 @@ import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
@@ -47,6 +36,18 @@ import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; 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 public class VpnStateFragment extends Fragment implements VpnStateListener
{ {
private static final String KEY_ERROR_CONNECTION_ID = "error_connection_id"; 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 mProfileNameView;
private TextView mProfileView; private TextView mProfileView;
private TextView mStateView; private TextView mStateView;
private int stateBaseColor; private int mColorStateBase;
private int mColorStateError;
private int mColorStateSuccess;
private Button mActionButton; private Button mActionButton;
private ProgressDialog mConnectDialog; private ProgressDialog mConnectDialog;
private ProgressDialog mDisconnectDialog; private ProgressDialog mDisconnectDialog;
@@ -64,7 +67,8 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
private long mErrorConnectionID; private long mErrorConnectionID;
private long mDismissedConnectionID; private long mDismissedConnectionID;
private VpnStateService mService; private VpnStateService mService;
private final ServiceConnection mServiceConnection = new ServiceConnection() { private final ServiceConnection mServiceConnection = new ServiceConnection()
{
@Override @Override
public void onServiceDisconnected(ComponentName name) public void onServiceDisconnected(ComponentName name)
{ {
@@ -85,6 +89,9 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
{ {
super.onCreate(savedInstanceState); 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 */ /* bind to the service only seems to work from the ApplicationContext */
Context context = getActivity().getApplicationContext(); Context context = getActivity().getApplicationContext();
context.bindService(new Intent(context, VpnStateService.class), 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); View view = inflater.inflate(R.layout.vpn_state_fragment, null);
mActionButton = (Button)view.findViewById(R.id.action); mActionButton = (Button)view.findViewById(R.id.action);
mActionButton.setOnClickListener(new OnClickListener() { mActionButton.setOnClickListener(new OnClickListener()
{
@Override @Override
public void onClick(View v) public void onClick(View v)
{ {
@@ -128,7 +136,7 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
enableActionButton(false); enableActionButton(false);
mStateView = (TextView)view.findViewById(R.id.vpn_state); mStateView = (TextView)view.findViewById(R.id.vpn_state);
stateBaseColor = mStateView.getCurrentTextColor(); mColorStateBase = mStateView.getCurrentTextColor();
mProfileView = (TextView)view.findViewById(R.id.vpn_profile_label); mProfileView = (TextView)view.findViewById(R.id.vpn_profile_label);
mProfileNameView = (TextView)view.findViewById(R.id.vpn_profile_name); mProfileNameView = (TextView)view.findViewById(R.id.vpn_profile_name);
@@ -203,26 +211,26 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
showProfile(false); showProfile(false);
hideProgressDialog(); hideProgressDialog();
mStateView.setText(R.string.state_disabled); mStateView.setText(R.string.state_disabled);
mStateView.setTextColor(stateBaseColor); mStateView.setTextColor(mColorStateBase);
break; break;
case CONNECTING: case CONNECTING:
showProfile(true); showProfile(true);
showConnectDialog(name, gateway); showConnectDialog(name, gateway);
mStateView.setText(R.string.state_connecting); mStateView.setText(R.string.state_connecting);
mStateView.setTextColor(stateBaseColor); mStateView.setTextColor(mColorStateBase);
break; break;
case CONNECTED: case CONNECTED:
showProfile(true); showProfile(true);
hideProgressDialog(); hideProgressDialog();
enableActionButton(true); enableActionButton(true);
mStateView.setText(R.string.state_connected); mStateView.setText(R.string.state_connected);
mStateView.setTextColor(getResources().getColor(R.color.success_text)); mStateView.setTextColor(mColorStateSuccess);
break; break;
case DISCONNECTING: case DISCONNECTING:
showProfile(true); showProfile(true);
showDisconnectDialog(name); showDisconnectDialog(name);
mStateView.setText(R.string.state_disconnecting); mStateView.setText(R.string.state_disconnecting);
mStateView.setTextColor(stateBaseColor); mStateView.setTextColor(mColorStateBase);
break; break;
} }
} }
@@ -251,7 +259,7 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
showProfile(true); showProfile(true);
enableActionButton(false); enableActionButton(false);
mStateView.setText(R.string.state_error); mStateView.setText(R.string.state_error);
mStateView.setTextColor(getResources().getColor(R.color.error_text)); mStateView.setTextColor(mColorStateError);
switch (error) switch (error)
{ {
case AUTH_FAILED: case AUTH_FAILED:
@@ -334,18 +342,18 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
mConnectDialog.setIndeterminate(true); mConnectDialog.setIndeterminate(true);
mConnectDialog.setCancelable(false); mConnectDialog.setCancelable(false);
mConnectDialog.setButton(DialogInterface.BUTTON_NEGATIVE, mConnectDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
getString(android.R.string.cancel), getString(android.R.string.cancel),
new DialogInterface.OnClickListener() new DialogInterface.OnClickListener()
{ {
@Override @Override
public void onClick(DialogInterface dialog, int which) public void onClick(DialogInterface dialog, int which)
{ {
if (mService != null) if (mService != null)
{ {
mService.disconnect(); mService.disconnect();
} }
} }
}); });
mConnectDialog.show(); mConnectDialog.show();
mProgressDialog = mConnectDialog; mProgressDialog = mConnectDialog;
} }
@@ -374,7 +382,8 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
mErrorDialog = new AlertDialog.Builder(getActivity()) mErrorDialog = new AlertDialog.Builder(getActivity())
.setMessage(getString(R.string.error_introduction) + " " + getString(textid)) .setMessage(getString(R.string.error_introduction) + " " + getString(textid))
.setCancelable(false) .setCancelable(false)
.setNeutralButton(text, new DialogInterface.OnClickListener() { .setNeutralButton(text, new DialogInterface.OnClickListener()
{
@Override @Override
public void onClick(DialogInterface dialog, int which) public void onClick(DialogInterface dialog, int which)
{ {
@@ -394,7 +403,8 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
startActivity(intent); startActivity(intent);
} }
}) })
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
{
@Override @Override
public void onClick(DialogInterface dialog, int id) public void onClick(DialogInterface dialog, int id)
{ {
@@ -402,7 +412,8 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
dialog.dismiss(); dialog.dismiss();
} }
}).create(); }).create();
mErrorDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { mErrorDialog.setOnDismissListener(new DialogInterface.OnDismissListener()
{
@Override @Override
public void onDismiss(DialogInterface dialog) public void onDismiss(DialogInterface dialog)
{ {
@@ -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>
@@ -33,7 +33,8 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="9sp" android:textSize="9sp"
android:typeface="monospace" > android:typeface="monospace"
android:fontFamily="monospace" >
</TextView> </TextView>
</org.strongswan.android.ui.LogScrollView> </org.strongswan.android.ui.LogScrollView>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012 Tobias Brunner Copyright (C) 2012-2015 Tobias Brunner
Hochschule fuer Technik Rapperswil Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it This program is free software; you can redistribute it and/or modify it
@@ -13,8 +13,23 @@
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details. for more details.
--> -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent" > 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>
@@ -13,16 +13,17 @@
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details. 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 <item
android:id="@+id/menu_import_certificate" android:id="@+id/menu_import_certificate"
android:title="@string/import_certificate" android:title="@string/import_certificate"
android:showAsAction="withText" /> app:showAsAction="withText" />
<item <item
android:id="@+id/menu_reload_certs" android:id="@+id/menu_reload_certs"
android:title="@string/reload_trusted_certs" android:title="@string/reload_trusted_certs"
android:showAsAction="withText" /> app:showAsAction="withText" />
</menu> </menu>
@@ -13,11 +13,12 @@
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details. 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 <item
android:id="@+id/menu_send_log" android:id="@+id/menu_send_log"
android:title="@string/send_log" android:title="@string/send_log"
android:showAsAction="ifRoom|withText" /> app:showAsAction="ifRoom|withText" />
</menu> </menu>
@@ -13,16 +13,17 @@
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details. 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 <item
android:id="@+id/menu_manage_certs" android:id="@+id/menu_manage_certs"
android:title="@string/trusted_certs_title" android:title="@string/trusted_certs_title"
android:showAsAction="withText" /> app:showAsAction="withText" />
<item <item
android:id="@+id/menu_show_log" android:id="@+id/menu_show_log"
android:title="@string/show_log" android:title="@string/show_log"
android:showAsAction="withText" /> app:showAsAction="withText" />
</menu> </menu>
@@ -13,16 +13,17 @@
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details. 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 <item
android:id="@+id/menu_accept" android:id="@+id/menu_accept"
android:title="@string/profile_edit_save" android:title="@string/profile_edit_save"
android:showAsAction="always|withText" /> app:showAsAction="always|withText" />
<item <item
android:id="@+id/menu_cancel" android:id="@+id/menu_cancel"
android:title="@string/profile_edit_cancel" android:title="@string/profile_edit_cancel"
android:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
</menu> </menu>
@@ -13,10 +13,11 @@
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details. 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" <item android:id="@+id/add_profile"
android:title="@string/add_profile" android:title="@string/add_profile"
android:showAsAction="always|withText" /> app:showAsAction="always|withText" />
</menu> </menu>
@@ -16,9 +16,9 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/edit_profile" <item android:id="@+id/edit_profile"
android:title="@string/edit_profile" ></item> android:title="@string/edit_profile" />
<item android:id="@+id/delete_profile" <item android:id="@+id/delete_profile"
android:title="@string/delete_profile" ></item> android:title="@string/delete_profile" />
</menu> </menu>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?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 Giuliano Grassi
Copyright (C) 2012 Ralf Sager 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 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 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_save">Speichern</string>
<string name="profile_edit_cancel">Abbrechen</string> <string name="profile_edit_cancel">Abbrechen</string>
<string name="profile_name_label">Profilname:</string> <string name="profile_name_label">Profilname:</string>
<string name="profile_name_hint">(Gateway-Adresse verwenden)</string> <string name="profile_name_hint">(Server-Adresse verwenden)</string>
<string name="profile_gateway_label">Gateway:</string> <string name="profile_gateway_label">Server:</string>
<string name="profile_vpn_type_label">Typ:</string> <string name="profile_vpn_type_label">Typ:</string>
<string name="profile_username_label">Benutzername:</string> <string name="profile_username_label">Benutzername:</string>
<string name="profile_password_label">Passwort:</string> <string name="profile_password_label">Passwort:</string>
@@ -71,14 +71,14 @@
<string name="profile_split_tunnelingv4_title">Blockiere IPv4 Verkehr der nicht für das VPN bestimmt ist</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> <string name="profile_split_tunnelingv6_title">Blockiere IPv6 Verkehr der nicht für das VPN bestimmt ist</string>
<!-- Warnings/Notifications in the details view --> <!-- 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_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_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_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="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_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_subtitle">Gerätedaten werden an den Server-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_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 --> <!-- Trusted certificate selection -->
<string name="trusted_certs_title">CA-Zertifikate</string> <string name="trusted_certs_title">CA-Zertifikate</string>
@@ -116,9 +116,9 @@
<string name="login_title">Passwort eingeben um zu verbinden</string> <string name="login_title">Passwort eingeben um zu verbinden</string>
<string name="login_confirm">Verbinden</string> <string name="login_confirm">Verbinden</string>
<string name="error_introduction">Fehler beim Aufsetzen des VPN:</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_lookup_failed">Server-Adresse konnte nicht aufgelöst werden.</string>
<string name="error_unreachable">Gateway ist nicht erreichbar.</string> <string name="error_unreachable">Server ist nicht erreichbar.</string>
<string name="error_peer_auth_failed">Authentifizierung des Gateway ist fehlgeschlagen.</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_auth_failed">Benutzerauthentifizierung ist fehlgeschlagen.</string>
<string name="error_assessment_failed">Sicherheitsassessment ist fehlgeschlagen.</string> <string name="error_assessment_failed">Sicherheitsassessment ist fehlgeschlagen.</string>
<string name="error_generic">Unbekannter Fehler während des Verbindens.</string> <string name="error_generic">Unbekannter Fehler während des Verbindens.</string>
@@ -50,8 +50,8 @@
<string name="profile_edit_save">Zapisz</string> <string name="profile_edit_save">Zapisz</string>
<string name="profile_edit_cancel">Anuluj</string> <string name="profile_edit_cancel">Anuluj</string>
<string name="profile_name_label">Nazwa profilu:</string> <string name="profile_name_label">Nazwa profilu:</string>
<string name="profile_name_hint">(użyj adresu bramki)</string> <string name="profile_name_hint">(użyj adresu serwer)</string>
<string name="profile_gateway_label">Bramka:</string> <string name="profile_gateway_label">Serwer:</string>
<string name="profile_vpn_type_label">Typ:</string> <string name="profile_vpn_type_label">Typ:</string>
<string name="profile_username_label">Użytkownik:</string> <string name="profile_username_label">Użytkownik:</string>
<string name="profile_password_label">Hasło:</string> <string name="profile_password_label">Hasło:</string>
@@ -71,14 +71,14 @@
<string name="profile_split_tunnelingv4_title">Block IPv4 traffic not destined for the VPN</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> <string name="profile_split_tunnelingv6_title">Block IPv6 traffic not destined for the VPN</string>
<!-- Warnings/Notifications in the details view --> <!-- 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_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_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_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="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_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_subtitle">Device data is sent to the server 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_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 --> <!-- Trusted certificate selection -->
<string name="trusted_certs_title">Certyfikaty CA</string> <string name="trusted_certs_title">Certyfikaty CA</string>
@@ -116,9 +116,9 @@
<string name="login_title">Wprowadż hasło</string> <string name="login_title">Wprowadż hasło</string>
<string name="login_confirm">Połącz</string> <string name="login_confirm">Połącz</string>
<string name="error_introduction">Nie udało się utworzyć tunelu VPN:</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_lookup_failed">Nie znaleziono adresu serwer</string>
<string name="error_unreachable">Bramka jest nieosiągalna</string> <string name="error_unreachable">Serwer jest nieosiągalna</string>
<string name="error_peer_auth_failed">Błąd przy weryfikacji bramki</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_auth_failed">Błąd przy autoryzacji użytkownika</string>
<string name="error_assessment_failed">Security assessment failed.</string> <string name="error_assessment_failed">Security assessment failed.</string>
<string name="error_generic">Nieznany błąd w czasie połączenia</string> <string name="error_generic">Nieznany błąd w czasie połączenia</string>
@@ -47,8 +47,8 @@
<string name="profile_edit_save">Сохранить</string> <string name="profile_edit_save">Сохранить</string>
<string name="profile_edit_cancel">Отмена</string> <string name="profile_edit_cancel">Отмена</string>
<string name="profile_name_label">Название профиля:</string> <string name="profile_name_label">Название профиля:</string>
<string name="profile_name_hint">(адрес шлюза)</string> <string name="profile_name_hint">(адрес cервер)</string>
<string name="profile_gateway_label">Шлюз:</string> <string name="profile_gateway_label">Сервер:</string>
<string name="profile_vpn_type_label">Тип:</string> <string name="profile_vpn_type_label">Тип:</string>
<string name="profile_username_label">Логин:</string> <string name="profile_username_label">Логин:</string>
<string name="profile_password_label">Пароль:</string> <string name="profile_password_label">Пароль:</string>
@@ -68,14 +68,14 @@
<string name="profile_split_tunnelingv4_title">Block IPv4 traffic not destined for the VPN</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> <string name="profile_split_tunnelingv6_title">Block IPv6 traffic not destined for the VPN</string>
<!-- Warnings/Notifications in the details view --> <!-- 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_no_input_username">Пожалуйста введите имя пользователя</string>
<string name="alert_text_nocertfound_title">Не выбран сертификат CA</string> <string name="alert_text_nocertfound_title">Не выбран сертификат CA</string>
<string name="alert_text_nocertfound">Пожалуйста выберите один <i>Выбрать автоматически</i></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="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_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_subtitle">Device data is sent to the server 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_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 --> <!-- Trusted certificate selection -->
<string name="trusted_certs_title">Сертификаты CA</string> <string name="trusted_certs_title">Сертификаты CA</string>
@@ -113,9 +113,9 @@
<string name="login_title">Введите пароль для соединения</string> <string name="login_title">Введите пароль для соединения</string>
<string name="login_confirm">Соединить</string> <string name="login_confirm">Соединить</string>
<string name="error_introduction">Ошибка подключения к VPN:</string> <string name="error_introduction">Ошибка подключения к VPN:</string>
<string name="error_lookup_failed">Не найден адрес шлюза.</string> <string name="error_lookup_failed">Не найден адрес сервер.</string>
<string name="error_unreachable">Шлюз недоступен.</string> <string name="error_unreachable">Сервер недоступен.</string>
<string name="error_peer_auth_failed">Ошибка авторизаци при подключении к шлюзу.</string> <string name="error_peer_auth_failed">Ошибка авторизаци при подключении к сервер.</string>
<string name="error_auth_failed">Ошибка авторизации пользователя.</string> <string name="error_auth_failed">Ошибка авторизации пользователя.</string>
<string name="error_assessment_failed">Security assessment failed.</string> <string name="error_assessment_failed">Security assessment failed.</string>
<string name="error_generic">Неизвестная ошибка.</string> <string name="error_generic">Неизвестная ошибка.</string>
@@ -48,8 +48,8 @@
<string name="profile_edit_save">Зберегти</string> <string name="profile_edit_save">Зберегти</string>
<string name="profile_edit_cancel">Відміна</string> <string name="profile_edit_cancel">Відміна</string>
<string name="profile_name_label">Назва профілю:</string> <string name="profile_name_label">Назва профілю:</string>
<string name="profile_name_hint">(використовувати адресу шлюза)</string> <string name="profile_name_hint">(використовувати адресу cервер)</string>
<string name="profile_gateway_label">Шлюз:</string> <string name="profile_gateway_label">Сервер:</string>
<string name="profile_vpn_type_label">Тип:</string> <string name="profile_vpn_type_label">Тип:</string>
<string name="profile_username_label">Логін:</string> <string name="profile_username_label">Логін:</string>
<string name="profile_password_label">Пароль:</string> <string name="profile_password_label">Пароль:</string>
@@ -69,14 +69,14 @@
<string name="profile_split_tunnelingv4_title">Block IPv4 traffic not destined for the VPN</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> <string name="profile_split_tunnelingv6_title">Block IPv6 traffic not destined for the VPN</string>
<!-- Warnings/Notifications in the details view --> <!-- 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_no_input_username">Введіть ім\'я користувача тут</string>
<string name="alert_text_nocertfound_title">Не вибрано сертифікат CA</string> <string name="alert_text_nocertfound_title">Не вибрано сертифікат CA</string>
<string name="alert_text_nocertfound">Будь ласка виберіть один <i>Вибрати автоматично</i></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="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_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_subtitle">Device data is sent to the server 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_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 --> <!-- Trusted certificate selection -->
<string name="trusted_certs_title">Сертифікати CA</string> <string name="trusted_certs_title">Сертифікати CA</string>
@@ -114,9 +114,9 @@
<string name="login_title">Введіть пароль для з\'єднання</string> <string name="login_title">Введіть пароль для з\'єднання</string>
<string name="login_confirm">Підключити</string> <string name="login_confirm">Підключити</string>
<string name="error_introduction">Помилка підлючення VPN:</string> <string name="error_introduction">Помилка підлючення VPN:</string>
<string name="error_lookup_failed">Помилка пошуку адреси шлюза.</string> <string name="error_lookup_failed">Помилка пошуку адреси сервер.</string>
<string name="error_unreachable">Немає зв\'язку зі шлюзом.</string> <string name="error_unreachable">Сервер зв\'язку зі шлюзом.</string>
<string name="error_peer_auth_failed">Помилка перевірки данних аутентифікації шлюза.</string> <string name="error_peer_auth_failed">Помилка перевірки данних аутентифікації сервер.</string>
<string name="error_auth_failed">Помилка аутентифікації користувача.</string> <string name="error_auth_failed">Помилка аутентифікації користувача.</string>
<string name="error_assessment_failed">Security assessment failed.</string> <string name="error_assessment_failed">Security assessment failed.</string>
<string name="error_generic">Невідома помилка під час підключення.</string> <string name="error_generic">Невідома помилка під час підключення.</string>
@@ -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>
@@ -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>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012-2013 Tobias Brunner Copyright (C) 2012-2016 Tobias Brunner
Hochschule fuer Technik Rapperswil HSR Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it 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 under the terms of the GNU General Public License as published by the
@@ -15,6 +15,15 @@
--> -->
<resources> <resources>
<color
name="accent">#96BDC2</color>
<color
name="primary">#A2042C</color>
<color
name="primary_dark">#000000</color>
<color <color
name="error_text">#D9192C</color> name="error_text">#D9192C</color>
@@ -25,9 +34,12 @@
name="success_text">#99CC00</color> name="success_text">#99CC00</color>
<color <color
name="panel_background">#333333</color> name="panel_background">#444444</color>
<color <color
name="panel_separator">#5a5a5a</color> name="panel_separator">#5a5a5a</color>
<color
name="pressed">#5a5a5a</color>
</resources> </resources>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?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 Giuliano Grassi
Copyright (C) 2012 Ralf Sager 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 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 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_save">Save</string>
<string name="profile_edit_cancel">Cancel</string> <string name="profile_edit_cancel">Cancel</string>
<string name="profile_name_label">Profile Name:</string> <string name="profile_name_label">Profile Name:</string>
<string name="profile_name_hint">(use gateway address)</string> <string name="profile_name_hint">(use server address)</string>
<string name="profile_gateway_label">Gateway:</string> <string name="profile_gateway_label">Server:</string>
<string name="profile_vpn_type_label">Type:</string> <string name="profile_vpn_type_label">Type:</string>
<string name="profile_username_label">Username:</string> <string name="profile_username_label">Username:</string>
<string name="profile_password_label">Password:</string> <string name="profile_password_label">Password:</string>
@@ -71,14 +71,14 @@
<string name="profile_split_tunnelingv4_title">Block IPv4 traffic not destined for the VPN</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> <string name="profile_split_tunnelingv6_title">Block IPv6 traffic not destined for the VPN</string>
<!-- Warnings/Notifications in the details view --> <!-- 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_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_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_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="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_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_subtitle">Device data is sent to the server 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_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 --> <!-- Trusted certificate selection -->
<string name="trusted_certs_title">CA certificates</string> <string name="trusted_certs_title">CA certificates</string>
@@ -116,9 +116,9 @@
<string name="login_title">Enter password to connect</string> <string name="login_title">Enter password to connect</string>
<string name="login_confirm">Connect</string> <string name="login_confirm">Connect</string>
<string name="error_introduction">Failed to establish VPN:</string> <string name="error_introduction">Failed to establish VPN:</string>
<string name="error_lookup_failed">Gateway address lookup failed.</string> <string name="error_lookup_failed">Server address lookup failed.</string>
<string name="error_unreachable">Gateway is unreachable.</string> <string name="error_unreachable">Server is unreachable.</string>
<string name="error_peer_auth_failed">Verifying gateway authentication failed.</string> <string name="error_peer_auth_failed">Verifying server authentication failed.</string>
<string name="error_auth_failed">User authentication failed.</string> <string name="error_auth_failed">User authentication failed.</string>
<string name="error_assessment_failed">Security assessment failed.</string> <string name="error_assessment_failed">Security assessment failed.</string>
<string name="error_generic">Unspecified failure while connecting.</string> <string name="error_generic">Unspecified failure while connecting.</string>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012 Tobias Brunner Copyright (C) 2012-2016 Tobias Brunner
Hochschule fuer Technik Rapperswil HSR Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it 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 under the terms of the GNU General Public License as published by the
@@ -15,7 +15,15 @@
--> -->
<resources xmlns:android="http://schemas.android.com/apk/res/android"> <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> </style>
</resources> </resources>
+1 -1
View File
@@ -3,7 +3,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:1.3.0' classpath 'com.android.tools.build:gradle:2.1.0'
} }
} }
@@ -1,6 +1,6 @@
#Wed Apr 10 15:27:10 PDT 2013 #Wed Apr 13 11:22:32 CEST 2016
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists 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