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