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 | 58e2574f6a27930679f976278ad9c3dbc8d4ef2a (patch) | |
tree | ed66e30a6d1acf1fcb68672cb636507e0bd89d2a | |
parent | 488a41cc60636298581c2b44b4706b259fc98a36 (diff) |
Doing progress on the Preference dialog chaos
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; + } + + + + } |