android: Spinner added to select the VPN type
[strongswan.git] / src / frontends / android / src / org / strongswan / android / ui / VpnProfileDetailActivity.java
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * Hochschule fuer Technik Rapperswil
6 *
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>.
11 *
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
15 * for more details.
16 */
17
18 package org.strongswan.android.ui;
19
20 import java.security.cert.X509Certificate;
21
22 import org.strongswan.android.R;
23 import org.strongswan.android.data.TrustedCertificateEntry;
24 import org.strongswan.android.data.VpnProfile;
25 import org.strongswan.android.data.VpnProfileDataSource;
26 import org.strongswan.android.data.VpnType;
27 import org.strongswan.android.logic.TrustedCertificateManager;
28
29 import android.app.Activity;
30 import android.app.AlertDialog;
31 import android.content.DialogInterface;
32 import android.content.Intent;
33 import android.os.Bundle;
34 import android.util.Log;
35 import android.view.Menu;
36 import android.view.MenuInflater;
37 import android.view.MenuItem;
38 import android.view.View;
39 import android.view.View.OnClickListener;
40 import android.view.ViewGroup;
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.RelativeLayout;
48 import android.widget.Spinner;
49 import android.widget.TextView;
50
51 public class VpnProfileDetailActivity extends Activity
52 {
53 private static final int SELECT_TRUSTED_CERTIFICATE = 0;
54
55 private VpnProfileDataSource mDataSource;
56 private Long mId;
57 private TrustedCertificateEntry mCertEntry;
58 private VpnType mVpnType = VpnType.IKEV2_EAP;
59 private VpnProfile mProfile;
60 private EditText mName;
61 private EditText mGateway;
62 private Spinner mSelectVpnType;
63 private ViewGroup mUsernamePassword;
64 private EditText mUsername;
65 private EditText mPassword;
66 private CheckBox mCheckAuto;
67 private RelativeLayout mSelectCert;
68 private TextView mCertTitle;
69 private TextView mCertSubtitle;
70
71 @Override
72 public void onCreate(Bundle savedInstanceState)
73 {
74 super.onCreate(savedInstanceState);
75
76 /* the title is set when we load the profile, if any */
77 getActionBar().setDisplayHomeAsUpEnabled(true);
78
79 mDataSource = new VpnProfileDataSource(this);
80 mDataSource.open();
81
82 setContentView(R.layout.profile_detail_view);
83
84 mName = (EditText)findViewById(R.id.name);
85 mGateway = (EditText)findViewById(R.id.gateway);
86 mSelectVpnType = (Spinner)findViewById(R.id.vpn_type);
87
88 mUsernamePassword = (ViewGroup)findViewById(R.id.username_password_group);
89 mUsername = (EditText)findViewById(R.id.username);
90 mPassword = (EditText)findViewById(R.id.password);
91
92 mCheckAuto = (CheckBox)findViewById(R.id.ca_auto);
93 mSelectCert = (RelativeLayout)findViewById(R.id.select_certificate);
94 mCertTitle = (TextView)findViewById(R.id.select_certificate_title);
95 mCertSubtitle = (TextView)findViewById(R.id.select_certificate_subtitle);
96
97
98 mSelectVpnType.setOnItemSelectedListener(new OnItemSelectedListener() {
99 @Override
100 public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
101 {
102 mVpnType = VpnType.values()[position];
103 updateClientCredentialView();
104 }
105
106 @Override
107 public void onNothingSelected(AdapterView<?> parent)
108 { /* should not happen */
109 mVpnType = VpnType.IKEV2_EAP;
110 updateClientCredentialView();
111 }
112 });
113
114 mCheckAuto.setOnCheckedChangeListener(new OnCheckedChangeListener() {
115 @Override
116 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
117 {
118 updateCertificateSelector();
119 }
120 });
121
122 mSelectCert.setOnClickListener(new OnClickListener() {
123 @Override
124 public void onClick(View v)
125 {
126 Intent intent = new Intent(VpnProfileDetailActivity.this, TrustedCertificatesActivity.class);
127 startActivityForResult(intent, SELECT_TRUSTED_CERTIFICATE);
128 }
129 });
130
131 mId = savedInstanceState == null ? null : savedInstanceState.getLong(VpnProfileDataSource.KEY_ID);
132 if (mId == null)
133 {
134 Bundle extras = getIntent().getExtras();
135 mId = extras == null ? null : extras.getLong(VpnProfileDataSource.KEY_ID);
136 }
137
138 loadProfileData(savedInstanceState);
139
140 updateClientCredentialView();
141 updateCertificateSelector();
142 }
143
144 @Override
145 protected void onDestroy()
146 {
147 super.onDestroy();
148 mDataSource.close();
149 }
150
151 @Override
152 protected void onSaveInstanceState(Bundle outState)
153 {
154 super.onSaveInstanceState(outState);
155 if (mId != null)
156 {
157 outState.putLong(VpnProfileDataSource.KEY_ID, mId);
158 }
159 if (mCertEntry != null)
160 {
161 outState.putString(VpnProfileDataSource.KEY_CERTIFICATE, mCertEntry.getAlias());
162 }
163 }
164
165 @Override
166 public boolean onCreateOptionsMenu(Menu menu)
167 {
168 MenuInflater inflater = getMenuInflater();
169 inflater.inflate(R.menu.profile_edit, menu);
170 return true;
171 }
172
173 @Override
174 public boolean onOptionsItemSelected(MenuItem item)
175 {
176 switch (item.getItemId())
177 {
178 case android.R.id.home:
179 case R.id.menu_cancel:
180 finish();
181 return true;
182 case R.id.menu_accept:
183 saveProfile();
184 return true;
185 default:
186 return super.onOptionsItemSelected(item);
187 }
188 }
189
190 @Override
191 protected void onActivityResult(int requestCode, int resultCode, Intent data)
192 {
193 switch (requestCode)
194 {
195 case SELECT_TRUSTED_CERTIFICATE:
196 if (resultCode == RESULT_OK)
197 {
198 String alias = data.getStringExtra(VpnProfileDataSource.KEY_CERTIFICATE);
199 X509Certificate certificate = TrustedCertificateManager.getInstance().getCACertificateFromAlias(alias);
200 mCertEntry = certificate == null ? null : new TrustedCertificateEntry(alias, certificate);
201 updateCertificateSelector();
202 }
203 break;
204 default:
205 super.onActivityResult(requestCode, resultCode, data);
206 }
207 }
208
209 /**
210 * Update the UI to enter client credentials depending on the type of VPN currently selected
211 */
212 private void updateClientCredentialView()
213 {
214 mUsernamePassword.setVisibility(mVpnType.getRequiresUsernamePassword() ? View.VISIBLE : View.GONE);
215 }
216
217 /**
218 * Show an alert in case the previously selected certificate is not found anymore
219 * or the user did not select a certificate in the spinner.
220 */
221 private void showCertificateAlert()
222 {
223 AlertDialog.Builder adb = new AlertDialog.Builder(VpnProfileDetailActivity.this);
224 adb.setTitle(R.string.alert_text_nocertfound_title);
225 adb.setMessage(R.string.alert_text_nocertfound);
226 adb.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
227 @Override
228 public void onClick(DialogInterface dialog, int id)
229 {
230 dialog.cancel();
231 }
232 });
233 adb.show();
234 }
235
236 /**
237 * Update the CA certificate selection UI depending on whether the
238 * certificate should be automatically selected or not.
239 */
240 private void updateCertificateSelector()
241 {
242 if (!mCheckAuto.isChecked())
243 {
244 mSelectCert.setEnabled(true);
245 mSelectCert.setVisibility(View.VISIBLE);
246
247 if (mCertEntry != null)
248 {
249 mCertTitle.setText(mCertEntry.getSubjectPrimary());
250 mCertSubtitle.setText(mCertEntry.getSubjectSecondary());
251 }
252 else
253 {
254 mCertTitle.setText(R.string.profile_ca_select_certificate_label);
255 mCertSubtitle.setText(R.string.profile_ca_select_certificate);
256 }
257 }
258 else
259 {
260 mSelectCert.setEnabled(false);
261 mSelectCert.setVisibility(View.GONE);
262 }
263 }
264
265 /**
266 * Save or update the profile depending on whether we actually have a
267 * profile object or not (this was created in updateProfileData)
268 */
269 private void saveProfile()
270 {
271 if (verifyInput())
272 {
273 if (mProfile != null)
274 {
275 updateProfileData();
276 mDataSource.updateVpnProfile(mProfile);
277 }
278 else
279 {
280 mProfile = new VpnProfile();
281 updateProfileData();
282 mDataSource.insertProfile(mProfile);
283 }
284 setResult(RESULT_OK, new Intent().putExtra(VpnProfileDataSource.KEY_ID, mProfile.getId()));
285 finish();
286 }
287 }
288
289 /**
290 * Verify the user input and display error messages.
291 * @return true if the input is valid
292 */
293 private boolean verifyInput()
294 {
295 boolean valid = true;
296 if (mGateway.getText().toString().trim().isEmpty())
297 {
298 mGateway.setError(getString(R.string.alert_text_no_input_gateway));
299 valid = false;
300 }
301 if (mVpnType.getRequiresUsernamePassword())
302 {
303 if (mUsername.getText().toString().trim().isEmpty())
304 {
305 mUsername.setError(getString(R.string.alert_text_no_input_username));
306 valid = false;
307 }
308 }
309 if (!mCheckAuto.isChecked() && mCertEntry == null)
310 {
311 showCertificateAlert();
312 valid = false;
313 }
314 return valid;
315 }
316
317 /**
318 * Update the profile object with the data entered by the user
319 */
320 private void updateProfileData()
321 {
322 /* the name is optional, we default to the gateway if none is given */
323 String name = mName.getText().toString().trim();
324 String gateway = mGateway.getText().toString().trim();
325 mProfile.setName(name.isEmpty() ? gateway : name);
326 mProfile.setGateway(gateway);
327 mProfile.setVpnType(mVpnType);
328 if (mVpnType.getRequiresUsernamePassword())
329 {
330 mProfile.setUsername(mUsername.getText().toString().trim());
331 String password = mPassword.getText().toString().trim();
332 password = password.isEmpty() ? null : password;
333 mProfile.setPassword(password);
334 }
335 String certAlias = mCheckAuto.isChecked() ? null : mCertEntry.getAlias();
336 mProfile.setCertificateAlias(certAlias);
337 }
338
339 /**
340 * Load an existing profile if we got an ID
341 *
342 * @param savedInstanceState previously saved state
343 */
344 private void loadProfileData(Bundle savedInstanceState)
345 {
346 String alias = null;
347
348 getActionBar().setTitle(R.string.add_profile);
349 if (mId != null)
350 {
351 mProfile = mDataSource.getVpnProfile(mId);
352 if (mProfile != null)
353 {
354 mName.setText(mProfile.getName());
355 mGateway.setText(mProfile.getGateway());
356 mVpnType = mProfile.getVpnType();
357 mUsername.setText(mProfile.getUsername());
358 mPassword.setText(mProfile.getPassword());
359 alias = mProfile.getCertificateAlias();
360 getActionBar().setTitle(mProfile.getName());
361 }
362 else
363 {
364 Log.e(VpnProfileDetailActivity.class.getSimpleName(),
365 "VPN profile with id " + mId + " not found");
366 finish();
367 }
368 }
369
370 mSelectVpnType.setSelection(mVpnType.ordinal());
371
372 /* check if the user selected a certificate previously */
373 alias = savedInstanceState == null ? alias : savedInstanceState.getString(VpnProfileDataSource.KEY_CERTIFICATE);
374 mCheckAuto.setChecked(alias == null);
375 if (alias != null)
376 {
377 X509Certificate certificate = TrustedCertificateManager.getInstance().getCACertificateFromAlias(alias);
378 if (certificate != null)
379 {
380 mCertEntry = new TrustedCertificateEntry(alias, certificate);
381 }
382 else
383 { /* previously selected certificate is not here anymore */
384 showCertificateAlert();
385 mCertEntry = null;
386 }
387 }
388 }
389 }