2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * Hochschule fuer Technik Rapperswil
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 package org
.strongswan
.android
.ui
;
20 import java
.security
.cert
.X509Certificate
;
21 import java
.util
.Hashtable
;
23 import org
.strongswan
.android
.R
;
24 import org
.strongswan
.android
.data
.VpnProfile
;
25 import org
.strongswan
.android
.data
.VpnProfileDataSource
;
26 import org
.strongswan
.android
.logic
.TrustedCertificateManager
;
27 import org
.strongswan
.android
.ui
.adapter
.TrustedCertificateAdapter
;
29 import android
.app
.Activity
;
30 import android
.app
.AlertDialog
;
31 import android
.content
.DialogInterface
;
32 import android
.content
.Intent
;
33 import android
.os
.AsyncTask
;
34 import android
.os
.Bundle
;
35 import android
.util
.Log
;
36 import android
.view
.Menu
;
37 import android
.view
.MenuInflater
;
38 import android
.view
.MenuItem
;
39 import android
.view
.View
;
40 import android
.view
.Window
;
41 import android
.widget
.AdapterView
;
42 import android
.widget
.AdapterView
.OnItemSelectedListener
;
43 import android
.widget
.CheckBox
;
44 import android
.widget
.CompoundButton
;
45 import android
.widget
.CompoundButton
.OnCheckedChangeListener
;
46 import android
.widget
.EditText
;
47 import android
.widget
.Spinner
;
49 public class VpnProfileDetailActivity
extends Activity
51 private VpnProfileDataSource mDataSource
;
53 private VpnProfile mProfile
;
54 private boolean mCertsLoaded
;
55 private String mCertAlias
;
56 private Spinner mCertSpinner
;
57 private TrustedCertificateAdapter
.CertEntry mSelectedCert
;
58 private EditText mName
;
59 private EditText mGateway
;
60 private EditText mUsername
;
61 private EditText mPassword
;
62 private CheckBox mCheckAll
;
63 private CheckBox mCheckAuto
;
66 public void onCreate(Bundle savedInstanceState
)
68 super.onCreate(savedInstanceState
);
69 requestWindowFeature(Window
.FEATURE_INDETERMINATE_PROGRESS
);
71 /* the title is set when we load the profile, if any */
72 getActionBar().setDisplayHomeAsUpEnabled(true
);
74 mDataSource
= new VpnProfileDataSource(this);
77 setContentView(R
.layout
.profile_detail_view
);
79 mName
= (EditText
)findViewById(R
.id
.name
);
80 mPassword
= (EditText
)findViewById(R
.id
.password
);
81 mGateway
= (EditText
)findViewById(R
.id
.gateway
);
82 mUsername
= (EditText
)findViewById(R
.id
.username
);
84 mCheckAll
= (CheckBox
)findViewById(R
.id
.ca_show_all
);
85 mCheckAuto
= (CheckBox
)findViewById(R
.id
.ca_auto
);
86 mCertSpinner
= (Spinner
)findViewById(R
.id
.ca_spinner
);
88 mCheckAuto
.setOnCheckedChangeListener(new OnCheckedChangeListener() {
90 public void onCheckedChanged(CompoundButton buttonView
, boolean isChecked
)
96 mCheckAll
.setOnCheckedChangeListener(new OnCheckedChangeListener() {
98 public void onCheckedChanged(CompoundButton buttonView
, boolean isChecked
)
100 Hashtable
<String
, X509Certificate
> certs
;
101 certs
= isChecked ? TrustedCertificateManager
.getInstance().getAllCACertificates()
102 : TrustedCertificateManager
.getInstance().getUserCACertificates();
103 mCertSpinner
.setAdapter(new TrustedCertificateAdapter(VpnProfileDetailActivity
.this, certs
));
104 mSelectedCert
= (TrustedCertificateAdapter
.CertEntry
)mCertSpinner
.getSelectedItem();
108 mCertSpinner
.setOnItemSelectedListener(new OnItemSelectedListener() {
110 public void onItemSelected(AdapterView
<?
> parent
, View view
,
113 mSelectedCert
= (TrustedCertificateAdapter
.CertEntry
)parent
.getSelectedItem();
117 public void onNothingSelected(AdapterView
<?
> arg0
)
119 mSelectedCert
= null
;
123 mId
= savedInstanceState
== null ? null
: savedInstanceState
.getLong(VpnProfileDataSource
.KEY_ID
);
126 Bundle extras
= getIntent().getExtras();
127 mId
= extras
== null ? null
: extras
.getLong(VpnProfileDataSource
.KEY_ID
);
132 new CertificateLoadTask().execute();
136 protected void onDestroy()
143 protected void onSaveInstanceState(Bundle outState
)
145 super.onSaveInstanceState(outState
);
146 outState
.putLong(VpnProfileDataSource
.KEY_ID
, mId
);
150 public boolean onCreateOptionsMenu(Menu menu
)
152 MenuInflater inflater
= getMenuInflater();
153 inflater
.inflate(R
.menu
.profile_edit
, menu
);
158 public boolean onOptionsItemSelected(MenuItem item
)
160 switch (item
.getItemId())
162 case android
.R
.id
.home
:
163 case R
.id
.menu_cancel
:
166 case R
.id
.menu_accept
:
170 return super.onOptionsItemSelected(item
);
175 * Show an alert in case the previously selected certificate is not found anymore
176 * or the user did not select a certificate in the spinner.
178 private void showCertificateAlert()
180 AlertDialog
.Builder adb
= new AlertDialog
.Builder(VpnProfileDetailActivity
.this);
181 adb
.setTitle(R
.string
.alert_text_nocertfound_title
);
182 adb
.setMessage(R
.string
.alert_text_nocertfound
);
183 adb
.setPositiveButton(android
.R
.string
.ok
, new DialogInterface
.OnClickListener() {
185 public void onClick(DialogInterface dialog
, int id
)
194 * Asynchronously executed task which confirms that the certificates are loaded.
195 * They are loaded from the main Activity already but might not be ready yet, or
198 * Once loaded the CA certificate spinner and checkboxes are updated
201 private class CertificateLoadTask
extends AsyncTask
<Void
, Void
, TrustedCertificateManager
>
204 protected void onPreExecute()
206 setProgressBarIndeterminateVisibility(true
);
210 protected TrustedCertificateManager
doInBackground(Void
... params
)
212 return TrustedCertificateManager
.getInstance().load();
216 protected void onPostExecute(TrustedCertificateManager result
)
218 TrustedCertificateAdapter adapter
;
219 if (mCertAlias
!= null
&& mCertAlias
.startsWith("system:"))
221 mCheckAll
.setChecked(true
);
222 adapter
= new TrustedCertificateAdapter(VpnProfileDetailActivity
.this,
223 result
.getAllCACertificates());
227 mCheckAll
.setChecked(false
);
228 adapter
= new TrustedCertificateAdapter(VpnProfileDetailActivity
.this,
229 result
.getUserCACertificates());
231 mCertSpinner
.setAdapter(adapter
);
233 if (mCertAlias
!= null
)
235 int position
= adapter
.getItemPosition(mCertAlias
);
237 { /* previously selected certificate is not here anymore */
238 showCertificateAlert();
242 mCertSpinner
.setSelection(position
);
246 mSelectedCert
= (TrustedCertificateAdapter
.CertEntry
)mCertSpinner
.getSelectedItem();
248 setProgressBarIndeterminateVisibility(false
);
255 * Update the CA certificate selection UI depending on whether the
256 * certificate should be automatically selected or not.
258 private void updateCertSpinner()
260 if (!mCheckAuto
.isChecked())
264 mCertSpinner
.setEnabled(true
);
265 mCertSpinner
.setVisibility(View
.VISIBLE
);
266 mCheckAll
.setEnabled(true
);
267 mCheckAll
.setVisibility(View
.VISIBLE
);
272 mCertSpinner
.setEnabled(false
);
273 mCertSpinner
.setVisibility(View
.GONE
);
274 mCheckAll
.setEnabled(false
);
275 mCheckAll
.setVisibility(View
.GONE
);
280 * Save or update the profile depending on whether we actually have a
281 * profile object or not (this was created in updateProfileData)
283 private void saveProfile()
287 if (mProfile
!= null
)
290 mDataSource
.updateVpnProfile(mProfile
);
294 mProfile
= new VpnProfile();
296 mDataSource
.insertProfile(mProfile
);
298 setResult(RESULT_OK
, new Intent().putExtra(VpnProfileDataSource
.KEY_ID
, mProfile
.getId()));
304 * Verify the user input and display error messages.
305 * @return true if the input is valid
307 private boolean verifyInput()
309 boolean valid
= true
;
310 if (mGateway
.getText().toString().trim().isEmpty())
312 mGateway
.setError(getString(R
.string
.alert_text_no_input_gateway
));
315 if (mUsername
.getText().toString().trim().isEmpty())
317 mUsername
.setError(getString(R
.string
.alert_text_no_input_username
));
320 if (!mCheckAuto
.isChecked() && mSelectedCert
== null
)
322 showCertificateAlert();
329 * Update the profile object with the data entered by the user
331 private void updateProfileData()
333 /* the name is optional, we default to the gateway if none is given */
334 String name
= mName
.getText().toString().trim();
335 String gateway
= mGateway
.getText().toString().trim();
336 mProfile
.setName(name
.isEmpty() ? gateway
: name
);
337 mProfile
.setGateway(gateway
);
338 mProfile
.setUsername(mUsername
.getText().toString().trim());
339 String password
= mPassword
.getText().toString().trim();
340 password
= password
.isEmpty() ? null
: password
;
341 mProfile
.setPassword(password
);
342 String certAlias
= mCheckAuto
.isChecked() ? null
: mSelectedCert
.mAlias
;
343 mProfile
.setCertificateAlias(certAlias
);
347 * Load an existing profile if we got an ID
349 private void loadProfileData()
351 getActionBar().setTitle(R
.string
.add_profile
);
354 mProfile
= mDataSource
.getVpnProfile(mId
);
355 if (mProfile
!= null
)
357 mName
.setText(mProfile
.getName());
358 mGateway
.setText(mProfile
.getGateway());
359 mUsername
.setText(mProfile
.getUsername());
360 mPassword
.setText(mProfile
.getPassword());
361 mCertAlias
= mProfile
.getCertificateAlias();
362 getActionBar().setTitle(mProfile
.getName());
366 Log
.e(VpnProfileDetailActivity
.class.getSimpleName(),
367 "VPN profile with id " + mId
+ " not found");
371 mCheckAll
.setChecked(false
);
372 mCheckAuto
.setChecked(mCertAlias
== null
);