diff options
| author | Arne Schwabe <arne@rfc2549.org> | 2012-04-23 00:07:02 +0200 | 
|---|---|---|
| committer | Arne Schwabe <arne@rfc2549.org> | 2012-04-23 00:07:02 +0200 | 
| commit | dca67df888680da70235ce402e42e05945f67cb8 (patch) | |
| tree | ed66e30a6d1acf1fcb68672cb636507e0bd89d2a | |
| parent | 488a41cc60636298581c2b44b4706b259fc98a36 (diff) | |
Doing progress on the Preference dialog chaos
--HG--
rename : res/layout/config.xml => res/layout/basic_settings.xml
rename : src/de/blinkt/openvpn/AboutActivity.java => src/de/blinkt/openvpn/AboutFragment.java
26 files changed, 847 insertions, 98 deletions
| diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 24c8f164..332947dc 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -24,27 +24,27 @@      <uses-sdk android:minSdkVersion="14" /> -    <!--  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> --> - +    <!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> -->      <application -	  android:debuggable="true"  +        android:debuggable="true"          android:icon="@drawable/icon"          android:label="@string/app" > -          <activity android:name="com.lamerman.FileDialog" /> -        <activity android:name=".AboutActivity" /> +        <activity android:name=".AboutFragment" />          <activity android:name=".VPNPreferences" />          <activity android:name=".LogWindow" /> -        <activity -            android:name=".OpenVPNClient" -            android:configChanges="orientation|keyboardHidden" > +        <activity android:name=".MainActivity" >              <intent-filter>                  <action android:name="android.intent.action.MAIN" />                  <category android:name="android.intent.category.LAUNCHER" />              </intent-filter>          </activity> +        <activity +            android:name=".OpenVPNClient" +            android:configChanges="orientation|keyboardHidden" > +        </activity>          <service              android:name=".OpenVpnService" diff --git a/README.txt b/README.txt new file mode 100644 index 00000000..059d45e7 --- /dev/null +++ b/README.txt @@ -0,0 +1,4 @@ +This is my first Android project, so some things my be done in a completly stupid way. + + +I am for example not really sure if it was a good idea to use the Preferences Framework for the preferences
\ No newline at end of file diff --git a/res/layout/config.xml b/res/layout/basic_settings.xml index cfe8c6e3..cfe8c6e3 100644 --- a/res/layout/config.xml +++ b/res/layout/basic_settings.xml diff --git a/res/layout/vpn_preference_layout.xml b/res/layout/vpn_preference_layout.xml index 4d1f7e2e..15fc91ab 100644 --- a/res/layout/vpn_preference_layout.xml +++ b/res/layout/vpn_preference_layout.xml @@ -79,7 +79,7 @@          android:background="@android:drawable/divider_horizontal_dark" />      <ImageView -        android:id="@+id/vpn_edit_settings" +        android:id="@+id/quickedit_settings"          android:layout_width="wrap_content"          android:layout_height="fill_parent"          android:layout_gravity="center" diff --git a/res/layout/vpn_preference_widget.xml b/res/layout/vpn_preference_widget.xml deleted file mode 100644 index fef23003..00000000 --- a/res/layout/vpn_preference_widget.xml +++ /dev/null @@ -1,8 +0,0 @@ -<CheckBox -    xmlns:android="http://schemas.android.com/apk/res/android" -    android:id="@+android:id/checkbox" -    android:layout_width="wrap_content" -    android:layout_height="wrap_content" -    android:layout_gravity="center" -    android:focusable="false" -    android:clickable="false" />
\ No newline at end of file diff --git a/res/values/arrays.xml b/res/values/arrays.xml index eb2c1b1c..41d523e3 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -8,6 +8,15 @@      		<item>Static Keys</item>      </string-array> +        <string-array name="vpn_entry_types"> +    		<item>certs</item> +    		<item>pkcs12</item> +    		<item>keystore</item> +    		<item>userpw</item> +    		<item>statickeys</item> +    </string-array> +    +          <string-array name="tls_directions">          <item>0</item>          <item>1</item> diff --git a/res/values/strings.xml b/res/values/strings.xml index a9c1b1dc..79b7f8a7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -93,8 +93,9 @@      <string name="auth_pwquery">Password</string>      <string name="static_keys_info">For the static configuration the TLS Auth Keys will be used as static keys.</string>      <string name="configure_the_vpn">Configure the VPN</string> -     -     +    <string name="menu_add_profile">Add Profile</string> +    <string name="add_profile_name_prompt">Enter a name identifying the new Profile</string> +    <string name="duplicate_profile_name">Duplicate Profile Name</string>  </resources> diff --git a/res/xml/main_about.xml b/res/xml/main_about.xml new file mode 100644 index 00000000..8e3e28dc --- /dev/null +++ b/res/xml/main_about.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > +    <de.blinkt.openvpn.AboutPreference /> + +</PreferenceScreen>
\ No newline at end of file diff --git a/res/xml/main_headers.xml b/res/xml/main_headers.xml new file mode 100644 index 00000000..a0c4f432 --- /dev/null +++ b/res/xml/main_headers.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<preference-headers xmlns:android="http://schemas.android.com/apk/res/android" > + +    <header +        android:fragment="de.blinkt.openvpn.VPNProfileList" +        android:summary="List of all VPN, confusing to be here :)" +        android:title="All your precious VPNs" /> +    <header +        android:fragment="de.blinkt.openvpn.AboutFragment" +        android:summary="About Openvpn for Android" +        android:title="About" /> +     + +</preference-headers>
\ No newline at end of file diff --git a/res/xml/vpn_authentification.xml b/res/xml/vpn_authentification.xml index 11ea3abe..949093d6 100644 --- a/res/xml/vpn_authentification.xml +++ b/res/xml/vpn_authentification.xml @@ -3,9 +3,9 @@      <CheckBoxPreference          android:key="remoteServerTLS" -        android:summary="Checks whether the server use a TLS Server Certificate" +        android:summary="Checks whether the server uses a TLS Server Certificate"          android:title="Except TLS Server" /> -    <de.blinkt.openvpn.VPNConfigPreference -        android:title="Whaaaaats UUUUuuuuup?" /> +     +    <CheckBoxPreference android:key="useTLSAuth"/>  </PreferenceScreen>
\ No newline at end of file diff --git a/res/xml/vpn_headers.xml b/res/xml/vpn_headers.xml index 7d0ade3f..424b4411 100644 --- a/res/xml/vpn_headers.xml +++ b/res/xml/vpn_headers.xml @@ -1,23 +1,20 @@  <?xml version="1.0" encoding="utf-8"?>  <preference-headers xmlns:android="http://schemas.android.com/apk/res/android" > -    <header android:summary="Server, port and authentication method. Normally you should only settings specified here." > -	    android:title="Basic Setting" -        <intent -            android:targetClass="de.blinkt.openvpn.OpenVPNClient" -            android:targetPackage="de.binkt.openvpn" /> -    </header> +    <header +        android:fragment="de.blinkt.openvpn.BasicSettings" +        android:summary="Server, port and authentication method. Normally you should only settings specified here." +        android:title="Basic Settings" />      <!-- android:icon="@drawable/ic_settings_applications" --> +      <header          android:fragment="de.blinkt.openvpn.VPNPreferences$IP_Settings"          android:summary="IP Address and Routing"          android:title="IP Settings" /> -     -        <header +    <header          android:fragment="de.blinkt.openvpn.VPNPreferences$Authentication"          android:summary="Authentication"          android:title="Authentication" /> -          <!-- android:icon="@drawable/ic_settings_display" -->      <header @@ -33,14 +30,9 @@              android:name="someKey"              android:value="someHeaderValue" />      </header> - -    <!-- android:icon="@drawable/ic_settings_display" -->      <header -        android:summary="Launches an Intent." -        android:title="Intent" > -        <intent -            android:action="android.intent.action.VIEW" -            android:data="http://www.android.com" /> -    </header> +        android:fragment="de.blinkt.openvpn.ShowConfigFragment" +        android:summary="Shows the generated openvpn Configuration File" +        android:title="Generated Config" />  </preference-headers>
\ No newline at end of file diff --git a/res/xml/vpn_overview.xml b/res/xml/vpn_overview.xml deleted file mode 100644 index 053f2526..00000000 --- a/res/xml/vpn_overview.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" -    android:title="@string/vpn_settings_activity_title" > - -    <PreferenceScreen -        android:key="new_vpn" -        android:title="@string/new_vpn" /> - -    <PreferenceCategory -        android:fragment="de.blinkt.openvpn.VPNList$ListFragment" -        android:key="vpn_list" -        android:title="@string/vpn" > -    </PreferenceCategory> - -</PreferenceScreen> diff --git a/res/xml/vpn_profile_list.xml b/res/xml/vpn_profile_list.xml new file mode 100644 index 00000000..b1ce1a1a --- /dev/null +++ b/res/xml/vpn_profile_list.xml @@ -0,0 +1,4 @@ +<PreferenceScreen +    xmlns:android="http://schemas.android.com/apk/res/android" +    xmlns:settings="http://schemas.android.com/apk/res/com.android.settings" +    android:key="profiles_list" />
\ No newline at end of file diff --git a/src/de/blinkt/openvpn/AboutActivity.java b/src/de/blinkt/openvpn/AboutActivity.java deleted file mode 100644 index 0361d67c..00000000 --- a/src/de/blinkt/openvpn/AboutActivity.java +++ /dev/null @@ -1,22 +0,0 @@ -package de.blinkt.openvpn; - -import android.app.Activity; -import android.os.Bundle; -import android.view.View; -import android.view.View.OnClickListener; - -public class AboutActivity extends Activity implements OnClickListener { - -    @Override -    public void onCreate(Bundle savedInstanceState) { -        super.onCreate(savedInstanceState); -        setContentView(R.layout.about); -         -        //findViewById(R.layout.about).setOnClickListener(this); -    } - -	@Override -	public void onClick(View v) { -		finish(); -	} -} diff --git a/src/de/blinkt/openvpn/AboutFragment.java b/src/de/blinkt/openvpn/AboutFragment.java new file mode 100644 index 00000000..a5b5695e --- /dev/null +++ b/src/de/blinkt/openvpn/AboutFragment.java @@ -0,0 +1,27 @@ +package de.blinkt.openvpn; + +import android.app.Activity; +import android.app.Fragment; +import android.os.Bundle; +import android.preference.PreferenceFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.View.OnClickListener; + +public class AboutFragment extends Fragment  { + +    @Override +    public void onCreate(Bundle savedInstanceState) { +        super.onCreate(savedInstanceState); +        +    } + +    @Override +    public View onCreateView(LayoutInflater inflater, ViewGroup container, +    		Bundle savedInstanceState) { +    	View v= inflater.inflate(R.layout.about, container, false); +    	return v; +    } + +} diff --git a/src/de/blinkt/openvpn/AboutPreference.java b/src/de/blinkt/openvpn/AboutPreference.java new file mode 100644 index 00000000..ff6c611d --- /dev/null +++ b/src/de/blinkt/openvpn/AboutPreference.java @@ -0,0 +1,14 @@ +package de.blinkt.openvpn; + +import android.content.Context; +import android.preference.Preference; +import android.util.AttributeSet; + +public class AboutPreference extends Preference { + +	public AboutPreference(Context context, AttributeSet attrs) { +		super(context, attrs); +		setWidgetLayoutResource(R.layout.about); +	} + +} diff --git a/src/de/blinkt/openvpn/BasicSettings.java b/src/de/blinkt/openvpn/BasicSettings.java new file mode 100644 index 00000000..271b8085 --- /dev/null +++ b/src/de/blinkt/openvpn/BasicSettings.java @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.blinkt.openvpn; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.Random; +import java.util.Vector; + +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import android.app.Activity; +import android.app.Fragment; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.VpnService; +import android.os.Bundle; +import android.os.Handler; +import android.os.Handler.Callback; +import android.os.Message; +import android.security.KeyChain; +import android.security.KeyChainAliasCallback; +import android.security.KeyChainException; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.ToggleButton; + +import com.lamerman.FileDialog; + +import de.blinkt.openvpn.R.id; + +public class BasicSettings extends Fragment implements View.OnClickListener, OnItemSelectedListener, Callback, OnCheckedChangeListener { +	private static final String TAG = "OpenVpnClient"; + + +	private static final int START_OPENVPN = 0; +	private static final int CHOOSE_FILE_OFFSET = 1000; +	private static final int UPDATE_ALIAS = 20; + +	private static final String PREFS_NAME = "OVPN_SERVER"; + +	private static final String OVPNCONFIGFILE = "android.conf"; +	private static final String OVPNCONFIGPKCS12 = "android.pkcs12"; + + +	private TextView mServerAddress; +	private TextView mServerPort; +	private FileSelectLayout mClientCert; +	private FileSelectLayout mCaCert; +	private FileSelectLayout mClientKey; +	private TextView mAliasName; +	private CheckBox mUseLzo; +	private ToggleButton mTcpUdp; +	private Spinner mType; +	private FileSelectLayout mpkcs12; +	private TextView mPKCS12Password; + +	private Handler mHandler; + + +	private CheckBox mUseTlsAuth; + + +	private CheckBox mShowAdvanced; + + +	private FileSelectLayout mTlsFile; + +	private HashMap<Integer, FileSelectLayout> fileselects = new HashMap<Integer, FileSelectLayout>(); + + +	private Spinner mTLSDirection; + + +	private EditText mUserName; + + +	private EditText mPassword; + + +	private View mView; + + +	private VpnProfile mProfile; + + + +	private void addFileSelectLayout (FileSelectLayout fsl) { +		int i = fileselects.size() + CHOOSE_FILE_OFFSET; +		fileselects.put(i, fsl); +		fsl.setActivity(getActivity(),i); +	} + +	public void onCreate(Bundle savedInstanceState) { +		super.onCreate(savedInstanceState); +	} + +	@Override +	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { +		 +		mView = inflater.inflate(R.layout.basic_settings,container,false); + + +		mServerAddress = (TextView) mView.findViewById(R.id.address); +		mServerPort = (TextView) mView.findViewById(R.id.port); +		mClientCert = (FileSelectLayout) mView.findViewById(R.id.certselect); +		mClientKey = (FileSelectLayout) mView.findViewById(R.id.keyselect); +		mCaCert = (FileSelectLayout) mView.findViewById(R.id.caselect); +		mpkcs12 = (FileSelectLayout) mView.findViewById(R.id.pkcs12select); +		mUseLzo = (CheckBox) mView.findViewById(R.id.lzo); +		mTcpUdp = (ToggleButton) mView.findViewById(id.tcpudp); +		mType = (Spinner) mView.findViewById(R.id.type); +		mPKCS12Password = (TextView) mView.findViewById(R.id.pkcs12password); +		mAliasName = (TextView) mView.findViewById(R.id.aliasname); +		mUseTlsAuth = (CheckBox) mView.findViewById(R.id.useTLSAuth); +		mTLSDirection = (Spinner) mView.findViewById(R.id.tls_direction); + +		mShowAdvanced = (CheckBox) mView.findViewById(R.id.show_advanced); +		mTlsFile = (FileSelectLayout) mView.findViewById(R.id.tlsAuth);		 +		mUserName = (EditText) mView.findViewById(R.id.auth_username); +		mPassword = (EditText) mView.findViewById(R.id.auth_password); +		 + +		addFileSelectLayout(mCaCert); +		addFileSelectLayout(mClientCert); +		addFileSelectLayout(mClientKey); +		addFileSelectLayout(mTlsFile); +		addFileSelectLayout(mpkcs12); + +		loadPreferences(); + +		mType.setOnItemSelectedListener(this); + +		mShowAdvanced.setOnCheckedChangeListener(this); +		mUseTlsAuth.setOnCheckedChangeListener(this); + + +		mView.findViewById(R.id.select_keystore_button).setOnClickListener(this); +		mView.findViewById(R.id.about).setOnClickListener(this); +		mView.findViewById(R.id.connect).setOnClickListener(this);		 + +		if (mHandler == null) { +			mHandler = new Handler(this); +		} +		return mView; +	} + + +	@Override +	public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { +		if (parent == mType) { +			changeType(position); +		} +	} + + + +	private void changeType(int type){ +		// hide everything +		mView.findViewById(R.id.pkcs12).setVisibility(View.GONE); +		mView.findViewById(R.id.certs).setVisibility(View.GONE); +		mView.findViewById(R.id.statickeys).setVisibility(View.GONE); +		mView.findViewById(R.id.keystore).setVisibility(View.GONE); + +		switch(type) { +		case VpnProfile.TYPE_CERTIFICATES: +			mView.findViewById(R.id.certs).setVisibility(View.VISIBLE); +			break; +		case VpnProfile.TYPE_PKCS12: +			mView.findViewById(R.id.pkcs12).setVisibility(View.VISIBLE); +			break; +		case VpnProfile.TYPE_STATICKEYS: +			mView.findViewById(R.id.statickeys).setVisibility(View.VISIBLE); +			break; +		case VpnProfile.TYPE_KEYSTORE: +			mView.findViewById(R.id.keystore).setVisibility(View.VISIBLE); +			break; +			 +		case VpnProfile.TYPE_USERPASS: +			mView.findViewById(R.id.userpassword).setVisibility(View.VISIBLE); +		} + + +	} + +	private void loadPreferences() { +		mProfile = ((VPNPreferences)getActivity()).getVPNProfile(); +		 +		mClientCert.setData(mProfile.mClientCertFilename); +		mClientKey.setData(mProfile.mClientKeyFilename); +		mCaCert.setData(mProfile.mCaFilename); + +		mUseLzo.setChecked(mProfile.mUseLzo); +		mServerPort.setText(mProfile.mServerPort); +		mServerAddress.setText(mProfile.mServerName); +		mTcpUdp.setChecked(mProfile.mUseUdp); +		mType.setSelection(mProfile.mAuthenticationType); +		mpkcs12.setData(mProfile.mPKCS12Filename); +		mPKCS12Password.setText(mProfile.mPKCS12Password); + +		mUseTlsAuth.setChecked(mProfile.mUseTLSAuth); +		onCheckedChanged(mUseTlsAuth,mUseTlsAuth.isChecked()); +		 +		mTlsFile.setData(mProfile.mTLSAuthFilename); +		mTLSDirection.setSelection(mProfile.mTLSAuthDirection); +		setAlias(); + +	} + +	private void savePreferences() { +		// We need an Editor object to make preference changes. +		// All objects are from android.context.Context + +		 +		mProfile.mCaFilename = mCaCert.getData(); +		mProfile.mClientCertFilename = mClientCert.getData(); +		mProfile.mClientKeyFilename = mClientKey.getData(); + +		mProfile.mUseLzo = mUseLzo.isChecked(); +		mProfile.mServerPort =mServerPort.getText().toString(); +		mProfile.mServerName = mServerAddress.getText().toString(); +		mProfile.mUseUdp = mTcpUdp.isChecked(); + +		mProfile.mAuthenticationType = mType.getSelectedItemPosition(); +		mProfile.mPKCS12Filename = mpkcs12.getData(); +		mProfile.mPKCS12Password = mPKCS12Password.getText().toString(); +		mProfile.mUseTLSAuth =mUseTlsAuth.isChecked(); +		mProfile.mTLSAuthFilename= mTlsFile.getData(); +		mProfile.mTLSAuthDirection =mTLSDirection.getSelectedItemPosition(); +		// Commit the edits! + +	} + + +	private void setAlias() { +		if(mProfile.mAlias == null) { +			mAliasName.setText(R.string.client_no_certificate); +		} else { +			mAliasName.setText(mProfile.mAlias); +		} +	} + +	public void showCertDialog () { +		KeyChain.choosePrivateKeyAlias(getActivity(), +				new KeyChainAliasCallback() { + +			public void alias(String alias) { +				// Credential alias selected.  Remember the alias selection for future use. +				mProfile.mAlias=alias; +				mHandler.sendEmptyMessage(UPDATE_ALIAS); +			} + + +		}, +		new String[] {"RSA", "DSA"}, // List of acceptable key types. null for any +		null,                        // issuer, null for any +		"internal.example.com",      // host name of server requesting the cert, null if unavailable +		443,                         // port of server requesting the cert, -1 if unavailable +		null);                       // alias to preselect, null if unavailable +	} + +	@Override +	public void onClick(View v) { +		if (v == mView.findViewById(R.id.select_keystore_button)) { +			showCertDialog(); +		} +	} + + + +	@Override +	public void onNothingSelected(AdapterView<?> parent) { +	} + + +	@Override +	public boolean handleMessage(Message msg) { +		setAlias(); +		return true; +	} + + +	@Override +	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { +		int visibility; +		if(isChecked)  +			visibility =View.VISIBLE; +		else  +			visibility =View.GONE; + +		if(buttonView==mShowAdvanced) { +			mView.findViewById(R.id.advanced_options).setVisibility(visibility); +		} else if (buttonView == mUseTlsAuth) { +			mView.findViewById(R.id.tlsauth_options).setVisibility(visibility); +		} +	} +} diff --git a/src/de/blinkt/openvpn/MainActivity.java b/src/de/blinkt/openvpn/MainActivity.java new file mode 100644 index 00000000..bc823745 --- /dev/null +++ b/src/de/blinkt/openvpn/MainActivity.java @@ -0,0 +1,13 @@ +package de.blinkt.openvpn; + +import java.util.List; + +import android.preference.PreferenceActivity; +import android.preference.PreferenceActivity.Header; + +public class MainActivity extends PreferenceActivity { +	@Override +	public void onBuildHeaders(List<Header> target) { +		loadHeadersFromResource(R.xml.main_headers, target);    +	} +} diff --git a/src/de/blinkt/openvpn/OpenVPNClient.java b/src/de/blinkt/openvpn/OpenVPNClient.java index f1a32b63..5af0ae8f 100644 --- a/src/de/blinkt/openvpn/OpenVPNClient.java +++ b/src/de/blinkt/openvpn/OpenVPNClient.java @@ -250,7 +250,7 @@ public class OpenVPNClient extends Activity implements View.OnClickListener, OnI  	@Override  	public void onCreate(Bundle savedInstanceState) {  		super.onCreate(savedInstanceState); -		setContentView(R.layout.config); +		setContentView(R.layout.basic_settings);  		// Forces early JNI Load  		OpenVPN.foo(); @@ -490,6 +490,7 @@ public class OpenVPNClient extends Activity implements View.OnClickListener, OnI  		} else if (v == findViewById(R.id.about)) {  			//Intent intent = new Intent(getBaseContext(),AboutActivity.class);  			Intent intent = new Intent(getBaseContext(),VPNPreferences.class); +			intent.putExtra("foo","der bar war hier!");  			startActivity(intent);  		} else if (v == findViewById(R.id.select_keystore_button)) {  			showCertDialog(); diff --git a/src/de/blinkt/openvpn/ShowConfigFragment.java b/src/de/blinkt/openvpn/ShowConfigFragment.java new file mode 100644 index 00000000..91471e84 --- /dev/null +++ b/src/de/blinkt/openvpn/ShowConfigFragment.java @@ -0,0 +1,8 @@ +package de.blinkt.openvpn; + +import android.app.Fragment; + + +public class ShowConfigFragment extends Fragment { + +} diff --git a/src/de/blinkt/openvpn/VPNConfigPreference.java b/src/de/blinkt/openvpn/VPNConfigPreference.java index 3afcfccb..0387ebdb 100644 --- a/src/de/blinkt/openvpn/VPNConfigPreference.java +++ b/src/de/blinkt/openvpn/VPNConfigPreference.java @@ -1,15 +1,55 @@  package de.blinkt.openvpn; -import android.content.Context; -import android.preference.CheckBoxPreference; +import android.os.Bundle;  import android.preference.Preference; -import android.util.AttributeSet; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageView; -public class VPNConfigPreference extends Preference { +public class VPNConfigPreference extends Preference implements OnClickListener { -	public VPNConfigPreference(Context context, AttributeSet attrs) { -		super(context, attrs); -	setWidgetLayoutResource(R.layout.vpn_preference_layout); + +	private OnQuickSettingsClickListener mOnQuickSettingsListener; +	private ImageView mQuickPrefButton; + + +	public VPNConfigPreference(VPNProfileList vpnProfileList, Bundle args) { + +		super(vpnProfileList.getActivity()); +		setWidgetLayoutResource(R.layout.vpn_preference_layout); + + +	} + +	@Override +	protected void onBindView(View view) { +		super.onBindView(view); +		mQuickPrefButton = (ImageView) view.findViewById(R.id.quickedit_settings); +		mQuickPrefButton.setOnClickListener(this);  	} +	public interface OnQuickSettingsClickListener { +		/** +		 * Called when a Preference has been clicked. +		 * +		 * @param preference The Preference that was clicked. +		 * @return True if the click was handled. +		 */ +		boolean onQuickSettingsClick(Preference preference); +	} + + +	public void setOnQuickSettingsClickListener(OnQuickSettingsClickListener onQuickSettingsListener) { +		mOnQuickSettingsListener = onQuickSettingsListener; +	} + +	@Override +	public void onClick(View v) { +		if (mOnQuickSettingsListener != null) { +			mOnQuickSettingsListener.onQuickSettingsClick(this); +		} + +	} + +  } diff --git a/src/de/blinkt/openvpn/VPNDatabase.java b/src/de/blinkt/openvpn/VPNDatabase.java new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/de/blinkt/openvpn/VPNDatabase.java diff --git a/src/de/blinkt/openvpn/VPNPreferenceFragment.java b/src/de/blinkt/openvpn/VPNPreferenceFragment.java new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/de/blinkt/openvpn/VPNPreferenceFragment.java diff --git a/src/de/blinkt/openvpn/VPNPreferences.java b/src/de/blinkt/openvpn/VPNPreferences.java index 69485efd..6c68e444 100644 --- a/src/de/blinkt/openvpn/VPNPreferences.java +++ b/src/de/blinkt/openvpn/VPNPreferences.java @@ -2,7 +2,9 @@ package de.blinkt.openvpn;  import java.util.List; +import android.content.Intent;  import android.os.Bundle; +import android.os.Parcelable;  import android.preference.CheckBoxPreference;  import android.preference.EditTextPreference;  import android.preference.Preference; @@ -16,6 +18,7 @@ import android.widget.Button;  public class VPNPreferences extends PreferenceActivity { +	private VpnProfile mProfile;  	public VPNPreferences() {  		super();  	} @@ -23,6 +26,8 @@ public class VPNPreferences extends PreferenceActivity {  	protected void onCreate(Bundle savedInstanceState) {  		super.onCreate(savedInstanceState); +		mProfile = getIntent().getParcelableExtra("VpnProfile"); +				  		if (hasHeaders()) {  			Button button = new Button(this);  			button.setText("Some action"); @@ -47,12 +52,13 @@ public class VPNPreferences extends PreferenceActivity {  		public void onCreate(Bundle savedInstanceState) {  			super.onCreate(savedInstanceState); +			  			// Make sure default values are applied.  In a real app, you would  			// want this in a shared function that is used to retrieve the  			// SharedPreferences wherever they are needed.  			PreferenceManager.setDefaultValues(getActivity(),  					R.xml.vpn_ipsettings, false); - +			  			// Load the preferences from an XML resource  			addPreferencesFromResource(R.xml.vpn_ipsettings);  			mIPv4 = (EditTextPreference) findPreference("ipv4_address"); @@ -69,8 +75,14 @@ public class VPNPreferences extends PreferenceActivity {  			mDNS2.setOnPreferenceChangeListener(this);  			mUsePull.setOnPreferenceChangeListener(this);  			mOverrideDNS.setOnPreferenceChangeListener(this); +			 +			 +			VpnProfile vp = ((VPNPreferences) getActivity()).getVPNProfile(); +			 +			  			setDNSState(); +			  		}  		@Override @@ -134,5 +146,8 @@ public class VPNPreferences extends PreferenceActivity {  			addPreferencesFromResource(R.xml.vpn_obscure);  		}  	} +	public VpnProfile getVPNProfile() { +		return mProfile; +	}  } diff --git a/src/de/blinkt/openvpn/VPNProfileList.java b/src/de/blinkt/openvpn/VPNProfileList.java index fb7af280..74c857d3 100644 --- a/src/de/blinkt/openvpn/VPNProfileList.java +++ b/src/de/blinkt/openvpn/VPNProfileList.java @@ -1,22 +1,233 @@  package de.blinkt.openvpn; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.StreamCorruptedException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import de.blinkt.openvpn.VPNConfigPreference.OnQuickSettingsClickListener; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor;  import android.os.Bundle; -import android.preference.PreferenceActivity; +import android.os.Parcelable; +import android.preference.DialogPreference; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; +import android.preference.PreferenceFragment; +import android.preference.PreferenceScreen; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.widget.EditText; +import android.widget.Toast; + +public class VPNProfileList extends PreferenceFragment implements OnPreferenceClickListener, OnQuickSettingsClickListener { +	private static final String PREFS_NAME =  "VPNList"; + +	private static final int MENU_ADD_PROFILE = Menu.FIRST; + + +	private HashMap<String,VpnProfile> profiles; + +	@Override +	public void onCreate(Bundle savedInstanceState) { +		super.onCreate(savedInstanceState); +		addPreferencesFromResource(R.xml.vpn_profile_list); +		setHasOptionsMenu(true); + +	} + +	@Override +	public void onResume() { +		super.onResume(); +		refreshList(); + + +	} + +	@Override +	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { +		menu.add(0, MENU_ADD_PROFILE, 0, R.string.menu_add_profile) +				.setIcon(android.R.drawable.ic_menu_add) +				.setAlphabeticShortcut('a') +				.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM +						| MenuItem.SHOW_AS_ACTION_WITH_TEXT); +	} + + +	@Override +	public boolean onOptionsItemSelected(MenuItem item) { +		final int itemId = item.getItemId(); +		if (itemId == MENU_ADD_PROFILE) { +			onAddProfileClicked(); +			return true; +		} else { +			return super.onOptionsItemSelected(item); +		} +	} + +	private void onAddProfileClicked() { +		Context context = getActivity(); +		if (context != null) { +			final EditText entry = new EditText(context); +			entry.setSingleLine(); + +			AlertDialog.Builder dialog = new AlertDialog.Builder(context); +			dialog.setTitle(R.string.menu_add_profile); +			dialog.setMessage(R.string.add_profile_name_prompt); +			dialog.setView(entry); + + +			dialog.setPositiveButton(android.R.string.ok, +					new DialogInterface.OnClickListener() { +				@Override +				public void onClick(DialogInterface dialog, int which) { +					String name = entry.getText().toString(); +					if (getProfileByName(name)==null) { +						VpnProfile profile = new VpnProfile(name); +						addProfile(profile); +						refreshList(); +					} else { +						Toast.makeText(getActivity(), R.string.duplicate_profile_name, Toast.LENGTH_LONG).show(); +					} +				} + + +			}); +			dialog.setNegativeButton(android.R.string.cancel, +					new DialogInterface.OnClickListener() { +				@Override +				public void onClick(DialogInterface dialog, int which) { +				} +			}); +			dialog.create().show(); +		} + +	} + +	public VpnProfile getProfileByName(String name) { +		for (VpnProfile vpnp : profiles.values()) { +			if(vpnp.getName().equals(name)) { +				return vpnp; +			} +		} +		return null;			 +	} + +	private void addProfile(VpnProfile profile) { +		profiles.put(profile.getUUID().toString(),profile); +		Editor editor = getActivity().getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE).edit(); +		editor.putStringSet("vpnlist", profiles.keySet()); +		editor.commit(); +		saveProfile(profile); + +	} + + +	private void saveProfile(VpnProfile profile) { +		ObjectOutputStream vpnfile; +		try { +			vpnfile = new ObjectOutputStream(getActivity().openFileOutput((profile.getUUID().toString() + ".vp"),Activity.MODE_PRIVATE)); + +			vpnfile.writeObject(profile); +			vpnfile.flush(); +			vpnfile.close(); +		} catch (FileNotFoundException e) { + +			e.printStackTrace(); +		} catch (IOException e) { + +			e.printStackTrace(); +		} +	} + +	private void loadVPNList() { +		profiles = new HashMap<String, VpnProfile>(); +		SharedPreferences settings =getActivity().getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE); +		Set<String> vlist = settings.getStringSet("vpnlist", null); +		if(vlist==null){ +			vlist = new HashSet<String>(); +		} + +		for (String vpnentry : vlist) { +			try { +				ObjectInputStream vpnfile = new ObjectInputStream(getActivity().openFileInput(vpnentry + ".vp")); +				VpnProfile vp = ((VpnProfile) vpnfile.readObject()); + +				profiles.put(vp.getUUID().toString(), vp); + +			} catch (StreamCorruptedException e) { +				e.printStackTrace(); +			} catch (FileNotFoundException e) { +				e.printStackTrace(); +			} catch (IOException e) { +				e.printStackTrace(); +			} catch (ClassNotFoundException e) {  +				e.printStackTrace(); +			} +		} +	} + + +	public void refreshList() { +		PreferenceScreen plist = getPreferenceScreen(); +		if (plist != null) { +			plist.removeAll();  +			loadVPNList(); + +			for (VpnProfile vpnprofile: profiles.values()) { +				Bundle args = new Bundle(); +				//TODO + +				String profileuuid = vpnprofile.getUUID().toString(); + + +				args.putParcelable("Profile", vpnprofile); +				//args.putString("name", vpnentry); +				VPNConfigPreference vpref = new VPNConfigPreference(this, args); +				vpref.setKey(profileuuid); +				vpref.setTitle(vpnprofile.getName()); +				vpref.setPersistent(false); +				//				vpref.setSelectable(true); +				vpref.setOnPreferenceClickListener(this); +				vpref.setOnQuickSettingsClickListener(this); +				plist.addPreference(vpref); +			} + +		} +	} + +	@Override +	public boolean onPreferenceClick(Preference preference) { +		String key= preference.getKey(); + +		return true; -import android.app.ProfileManager; +	} -public class VPNProfileList extends PreferenceActivity { -    private ProfileManager mProfileManager; +	@Override +	public boolean onQuickSettingsClick(Preference preference) { +		String key = preference.getKey(); -    @Override -    public void onCreate(Bundle savedInstanceState) { -        super.onCreate(savedInstanceState); +		VpnProfile vprofile = profiles.get(key); -        if (getPreferenceManager() != null) { -            addPreferencesFromResource(R.xml.profiles_settings); -            mProfileManager = (ProfileManager) getActivity().getSystemService(PROFILE_SERVICE); +		Intent vprefintent = new Intent(getActivity(),VPNPreferences.class) +		.putExtra("VpnProfile", (Parcelable)vprofile); -        } -    } +		startActivity(vprefintent); +		return true; +	}  } diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index 8d5fbe32..0eddabaa 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -1,10 +1,114 @@  package de.blinkt.openvpn; -public class VpnProfile { +import java.io.Serializable; +import java.util.UUID; + +import android.os.Parcel; +import android.os.Parcelable; + +public class VpnProfile implements Parcelable, Serializable{ +	/** +	 *  +	 */ +	private static final long serialVersionUID = 7085688938959334563L;  	static final int TYPE_CERTIFICATES=0;  	static final int TYPE_PKCS12=1;  	static final int TYPE_KEYSTORE=2;  	public static final int TYPE_USERPASS = 3;  	public static final int TYPE_STATICKEYS = 4; + +	// Keep in order of parceling +	// Public attributes, since I got mad with getter/setter +	// set members to default values +	private UUID mUuid; +	public int mAuthenticationType = TYPE_KEYSTORE ; +	public String mName; +	public String mAlias; +	public String mClientCertFilename; +	public int mTLSAuthDirection=2; +	public String mTLSAuthFilename; +	public String mClientKeyFilename; +	public String mCaFilename; +	public boolean mUseLzo=true; +	public String mServerPort= "1194" ; +	public boolean mUseUdp = true; +	public String mPKCS12Filename; +	public String mPKCS12Password; +	public boolean mUseTLSAuth = false; +	public String mServerName = "openvpn.blinkt.de" ; + + +	public int describeContents() { +		return 0; +	} + +	public void writeToParcel(Parcel out, int flags) { +		out.writeInt(mAuthenticationType); +		out.writeLong(mUuid.getMostSignificantBits()); +		out.writeLong(mUuid.getLeastSignificantBits()); +		out.writeString(mName); +		out.writeString(mAlias); +		out.writeString(mClientCertFilename); +		out.writeInt(mTLSAuthDirection); +		out.writeString(mTLSAuthFilename); +		out.writeString(mClientKeyFilename); +		out.writeString(mCaFilename); +		out.writeValue(mUseLzo); +		out.writeString(mServerPort); +		out.writeValue(mUseUdp); +		out.writeString(mPKCS12Filename); +		out.writeString(mPKCS12Password); +		out.writeValue(mUseTLSAuth); +		out.writeString(mServerName); +	} + +	private VpnProfile(Parcel in) { +		mAuthenticationType = in.readInt(); +		mUuid = new UUID(in.readLong(), in.readLong()); +		mName = in.readString(); +		mAlias = in.readString(); +		mClientCertFilename = in.readString(); +		mTLSAuthDirection = in.readInt();  +		mTLSAuthFilename = in.readString(); +		mClientKeyFilename = in.readString(); +		mCaFilename = in.readString(); +		mUseLzo = (Boolean) in.readValue(null); +		mServerPort = in.readString(); +		mUseUdp = (Boolean) in.readValue(null); +		mPKCS12Filename = in.readString(); +		mPKCS12Password = in.readString(); +		mUseTLSAuth = (Boolean) in.readValue(null); +		mServerName = in.readString();  +	} + +	public static final Parcelable.Creator<VpnProfile> CREATOR +	= new Parcelable.Creator<VpnProfile>() { +		public VpnProfile createFromParcel(Parcel in) { +			return new VpnProfile(in); +		} + +		public VpnProfile[] newArray(int size) { +			return new VpnProfile[size]; +		} +	}; + +	public VpnProfile(String name) { +		mUuid = UUID.randomUUID(); +		mName = name; +	} + +	public UUID getUUID() { +		return mUuid; + +	} + +	public String getName() { +		// TODO Auto-generated method stub +		return mName; +	} + + +	 +  } | 
