android: Make remote identity configurable in the GUI
[strongswan.git] / src / frontends / android / app / src / main / java / org / strongswan / android / ui / VpnProfileDetailActivity.java
1 /*
2 * Copyright (C) 2012-2016 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * HSR 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 android.app.Dialog;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.Intent;
24 import android.os.AsyncTask;
25 import android.os.Bundle;
26 import android.security.KeyChain;
27 import android.security.KeyChainAliasCallback;
28 import android.security.KeyChainException;
29 import android.support.v7.app.AlertDialog;
30 import android.support.v7.app.AppCompatActivity;
31 import android.support.v7.app.AppCompatDialogFragment;
32 import android.text.Editable;
33 import android.text.Html;
34 import android.text.TextUtils;
35 import android.text.TextWatcher;
36 import android.util.Log;
37 import android.view.Menu;
38 import android.view.MenuInflater;
39 import android.view.MenuItem;
40 import android.view.View;
41 import android.view.View.OnClickListener;
42 import android.view.ViewGroup;
43 import android.widget.AdapterView;
44 import android.widget.AdapterView.OnItemSelectedListener;
45 import android.widget.CheckBox;
46 import android.widget.CompoundButton;
47 import android.widget.CompoundButton.OnCheckedChangeListener;
48 import android.widget.EditText;
49 import android.widget.RelativeLayout;
50 import android.widget.Spinner;
51 import android.widget.TextView;
52
53 import org.strongswan.android.R;
54 import org.strongswan.android.data.VpnProfile;
55 import org.strongswan.android.data.VpnProfileDataSource;
56 import org.strongswan.android.data.VpnType;
57 import org.strongswan.android.data.VpnType.VpnTypeFeature;
58 import org.strongswan.android.logic.TrustedCertificateManager;
59 import org.strongswan.android.security.TrustedCertificateEntry;
60 import org.strongswan.android.ui.widget.TextInputLayoutHelper;
61
62 import java.security.cert.X509Certificate;
63
64 public class VpnProfileDetailActivity extends AppCompatActivity
65 {
66 private static final int SELECT_TRUSTED_CERTIFICATE = 0;
67 private static final int MTU_MIN = 1280;
68 private static final int MTU_MAX = 1500;
69
70 private VpnProfileDataSource mDataSource;
71 private Long mId;
72 private TrustedCertificateEntry mCertEntry;
73 private String mUserCertLoading;
74 private TrustedCertificateEntry mUserCertEntry;
75 private VpnType mVpnType = VpnType.IKEV2_EAP;
76 private VpnProfile mProfile;
77 private EditText mName;
78 private TextInputLayoutHelper mNameWrap;
79 private EditText mGateway;
80 private TextInputLayoutHelper mGatewayWrap;
81 private Spinner mSelectVpnType;
82 private ViewGroup mUsernamePassword;
83 private EditText mUsername;
84 private TextInputLayoutHelper mUsernameWrap;
85 private EditText mPassword;
86 private ViewGroup mUserCertificate;
87 private RelativeLayout mSelectUserCert;
88 private CheckBox mCheckAuto;
89 private RelativeLayout mSelectCert;
90 private RelativeLayout mTncNotice;
91 private CheckBox mShowAdvanced;
92 private ViewGroup mAdvancedSettings;
93 private EditText mRemoteId;
94 private TextInputLayoutHelper mRemoteIdWrap;
95 private EditText mMTU;
96 private TextInputLayoutHelper mMTUWrap;
97 private EditText mPort;
98 private TextInputLayoutHelper mPortWrap;
99 private CheckBox mBlockIPv4;
100 private CheckBox mBlockIPv6;
101
102 @Override
103 public void onCreate(Bundle savedInstanceState)
104 {
105 super.onCreate(savedInstanceState);
106
107 /* the title is set when we load the profile, if any */
108 getSupportActionBar().setDisplayHomeAsUpEnabled(true);
109
110 mDataSource = new VpnProfileDataSource(this);
111 mDataSource.open();
112
113 setContentView(R.layout.profile_detail_view);
114
115 mName = (EditText)findViewById(R.id.name);
116 mNameWrap = (TextInputLayoutHelper)findViewById(R.id.name_wrap);
117 mGateway = (EditText)findViewById(R.id.gateway);
118 mGatewayWrap = (TextInputLayoutHelper) findViewById(R.id.gateway_wrap);
119 mSelectVpnType = (Spinner)findViewById(R.id.vpn_type);
120 mTncNotice = (RelativeLayout)findViewById(R.id.tnc_notice);
121
122 mUsernamePassword = (ViewGroup)findViewById(R.id.username_password_group);
123 mUsername = (EditText)findViewById(R.id.username);
124 mUsernameWrap = (TextInputLayoutHelper) findViewById(R.id.username_wrap);
125 mPassword = (EditText)findViewById(R.id.password);
126
127 mUserCertificate = (ViewGroup)findViewById(R.id.user_certificate_group);
128 mSelectUserCert = (RelativeLayout)findViewById(R.id.select_user_certificate);
129
130 mCheckAuto = (CheckBox)findViewById(R.id.ca_auto);
131 mSelectCert = (RelativeLayout)findViewById(R.id.select_certificate);
132
133 mShowAdvanced = (CheckBox)findViewById(R.id.show_advanced);
134 mAdvancedSettings = (ViewGroup)findViewById(R.id.advanced_settings);
135
136 mRemoteId = (EditText)findViewById(R.id.remote_id);
137 mRemoteIdWrap = (TextInputLayoutHelper) findViewById(R.id.remote_id_wrap);
138 mMTU = (EditText)findViewById(R.id.mtu);
139 mMTUWrap = (TextInputLayoutHelper) findViewById(R.id.mtu_wrap);
140 mPort = (EditText)findViewById(R.id.port);
141 mPortWrap = (TextInputLayoutHelper) findViewById(R.id.port_wrap);
142 mBlockIPv4 = (CheckBox)findViewById(R.id.split_tunneling_v4);
143 mBlockIPv6 = (CheckBox)findViewById(R.id.split_tunneling_v6);
144
145 mGateway.addTextChangedListener(new TextWatcher() {
146 @Override
147 public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
148
149 @Override
150 public void onTextChanged(CharSequence s, int start, int before, int count) {}
151
152 @Override
153 public void afterTextChanged(Editable s)
154 {
155 if (TextUtils.isEmpty(mGateway.getText()))
156 {
157 mNameWrap.setHelperText(getString(R.string.profile_name_hint));
158 mRemoteIdWrap.setHelperText(getString(R.string.profile_remote_id_hint));
159 }
160 else
161 {
162 mNameWrap.setHelperText(String.format(getString(R.string.profile_name_hint_gateway), mGateway.getText()));
163 mRemoteIdWrap.setHelperText(String.format(getString(R.string.profile_remote_id_hint_gateway), mGateway.getText()));
164 }
165 }
166 });
167
168 mSelectVpnType.setOnItemSelectedListener(new OnItemSelectedListener() {
169 @Override
170 public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
171 {
172 mVpnType = VpnType.values()[position];
173 updateCredentialView();
174 }
175
176 @Override
177 public void onNothingSelected(AdapterView<?> parent)
178 { /* should not happen */
179 mVpnType = VpnType.IKEV2_EAP;
180 updateCredentialView();
181 }
182 });
183
184 ((TextView)mTncNotice.findViewById(android.R.id.text1)).setText(R.string.tnc_notice_title);
185 ((TextView)mTncNotice.findViewById(android.R.id.text2)).setText(R.string.tnc_notice_subtitle);
186 mTncNotice.setOnClickListener(new OnClickListener() {
187 @Override
188 public void onClick(View v)
189 {
190 new TncNoticeDialog().show(VpnProfileDetailActivity.this.getSupportFragmentManager(), "TncNotice");
191 }
192 });
193
194 mSelectUserCert.setOnClickListener(new SelectUserCertOnClickListener());
195
196 mCheckAuto.setOnCheckedChangeListener(new OnCheckedChangeListener() {
197 @Override
198 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
199 {
200 updateCertificateSelector();
201 }
202 });
203
204 mSelectCert.setOnClickListener(new OnClickListener() {
205 @Override
206 public void onClick(View v)
207 {
208 Intent intent = new Intent(VpnProfileDetailActivity.this, TrustedCertificatesActivity.class);
209 intent.setAction(TrustedCertificatesActivity.SELECT_CERTIFICATE);
210 startActivityForResult(intent, SELECT_TRUSTED_CERTIFICATE);
211 }
212 });
213
214 mShowAdvanced.setOnCheckedChangeListener(new OnCheckedChangeListener() {
215 @Override
216 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
217 {
218 updateAdvancedSettings();
219 }
220 });
221
222 mId = savedInstanceState == null ? null : savedInstanceState.getLong(VpnProfileDataSource.KEY_ID);
223 if (mId == null)
224 {
225 Bundle extras = getIntent().getExtras();
226 mId = extras == null ? null : extras.getLong(VpnProfileDataSource.KEY_ID);
227 }
228
229 loadProfileData(savedInstanceState);
230
231 updateCredentialView();
232 updateCertificateSelector();
233 updateAdvancedSettings();
234 }
235
236 @Override
237 protected void onDestroy()
238 {
239 super.onDestroy();
240 mDataSource.close();
241 }
242
243 @Override
244 protected void onSaveInstanceState(Bundle outState)
245 {
246 super.onSaveInstanceState(outState);
247 if (mId != null)
248 {
249 outState.putLong(VpnProfileDataSource.KEY_ID, mId);
250 }
251 if (mUserCertEntry != null)
252 {
253 outState.putString(VpnProfileDataSource.KEY_USER_CERTIFICATE, mUserCertEntry.getAlias());
254 }
255 if (mCertEntry != null)
256 {
257 outState.putString(VpnProfileDataSource.KEY_CERTIFICATE, mCertEntry.getAlias());
258 }
259 }
260
261 @Override
262 public boolean onCreateOptionsMenu(Menu menu)
263 {
264 MenuInflater inflater = getMenuInflater();
265 inflater.inflate(R.menu.profile_edit, menu);
266 return true;
267 }
268
269 @Override
270 public boolean onOptionsItemSelected(MenuItem item)
271 {
272 switch (item.getItemId())
273 {
274 case android.R.id.home:
275 case R.id.menu_cancel:
276 finish();
277 return true;
278 case R.id.menu_accept:
279 saveProfile();
280 return true;
281 default:
282 return super.onOptionsItemSelected(item);
283 }
284 }
285
286 @Override
287 protected void onActivityResult(int requestCode, int resultCode, Intent data)
288 {
289 switch (requestCode)
290 {
291 case SELECT_TRUSTED_CERTIFICATE:
292 if (resultCode == RESULT_OK)
293 {
294 String alias = data.getStringExtra(VpnProfileDataSource.KEY_CERTIFICATE);
295 X509Certificate certificate = TrustedCertificateManager.getInstance().getCACertificateFromAlias(alias);
296 mCertEntry = certificate == null ? null : new TrustedCertificateEntry(alias, certificate);
297 updateCertificateSelector();
298 }
299 break;
300 default:
301 super.onActivityResult(requestCode, resultCode, data);
302 }
303 }
304
305 /**
306 * Update the UI to enter credentials depending on the type of VPN currently selected
307 */
308 private void updateCredentialView()
309 {
310 mUsernamePassword.setVisibility(mVpnType.has(VpnTypeFeature.USER_PASS) ? View.VISIBLE : View.GONE);
311 mUserCertificate.setVisibility(mVpnType.has(VpnTypeFeature.CERTIFICATE) ? View.VISIBLE : View.GONE);
312 mTncNotice.setVisibility(mVpnType.has(VpnTypeFeature.BYOD) ? View.VISIBLE : View.GONE);
313
314 if (mVpnType.has(VpnTypeFeature.CERTIFICATE))
315 {
316 if (mUserCertLoading != null)
317 {
318 ((TextView)mSelectUserCert.findViewById(android.R.id.text1)).setText(mUserCertLoading);
319 ((TextView)mSelectUserCert.findViewById(android.R.id.text2)).setText(R.string.loading);
320 }
321 else if (mUserCertEntry != null)
322 { /* clear any errors and set the new data */
323 ((TextView)mSelectUserCert.findViewById(android.R.id.text1)).setError(null);
324 ((TextView)mSelectUserCert.findViewById(android.R.id.text1)).setText(mUserCertEntry.getAlias());
325 ((TextView)mSelectUserCert.findViewById(android.R.id.text2)).setText(mUserCertEntry.getCertificate().getSubjectDN().toString());
326 }
327 else
328 {
329 ((TextView)mSelectUserCert.findViewById(android.R.id.text1)).setText(R.string.profile_user_select_certificate_label);
330 ((TextView)mSelectUserCert.findViewById(android.R.id.text2)).setText(R.string.profile_user_select_certificate);
331 }
332 }
333 }
334
335 /**
336 * Show an alert in case the previously selected certificate is not found anymore
337 * or the user did not select a certificate in the spinner.
338 */
339 private void showCertificateAlert()
340 {
341 AlertDialog.Builder adb = new AlertDialog.Builder(VpnProfileDetailActivity.this);
342 adb.setTitle(R.string.alert_text_nocertfound_title);
343 adb.setMessage(R.string.alert_text_nocertfound);
344 adb.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
345 @Override
346 public void onClick(DialogInterface dialog, int id)
347 {
348 dialog.cancel();
349 }
350 });
351 adb.show();
352 }
353
354 /**
355 * Update the CA certificate selection UI depending on whether the
356 * certificate should be automatically selected or not.
357 */
358 private void updateCertificateSelector()
359 {
360 if (!mCheckAuto.isChecked())
361 {
362 mSelectCert.setEnabled(true);
363 mSelectCert.setVisibility(View.VISIBLE);
364
365 if (mCertEntry != null)
366 {
367 ((TextView)mSelectCert.findViewById(android.R.id.text1)).setText(mCertEntry.getSubjectPrimary());
368 ((TextView)mSelectCert.findViewById(android.R.id.text2)).setText(mCertEntry.getSubjectSecondary());
369 }
370 else
371 {
372 ((TextView)mSelectCert.findViewById(android.R.id.text1)).setText(R.string.profile_ca_select_certificate_label);
373 ((TextView)mSelectCert.findViewById(android.R.id.text2)).setText(R.string.profile_ca_select_certificate);
374 }
375 }
376 else
377 {
378 mSelectCert.setEnabled(false);
379 mSelectCert.setVisibility(View.GONE);
380 }
381 }
382
383 /**
384 * Update the advanced settings UI depending on whether any advanced
385 * settings have already been made.
386 */
387 private void updateAdvancedSettings()
388 {
389 boolean show = mShowAdvanced.isChecked();
390 if (!show && mProfile != null)
391 {
392 Integer st = mProfile.getSplitTunneling();
393 show = mProfile.getRemoteId() != null || mProfile.getMTU() != null ||
394 mProfile.getPort() != null || (st != null && st != 0);
395 }
396 mShowAdvanced.setVisibility(!show ? View.VISIBLE : View.GONE);
397 mAdvancedSettings.setVisibility(show ? View.VISIBLE : View.GONE);
398 }
399
400 /**
401 * Save or update the profile depending on whether we actually have a
402 * profile object or not (this was created in updateProfileData)
403 */
404 private void saveProfile()
405 {
406 if (verifyInput())
407 {
408 if (mProfile != null)
409 {
410 updateProfileData();
411 mDataSource.updateVpnProfile(mProfile);
412 }
413 else
414 {
415 mProfile = new VpnProfile();
416 updateProfileData();
417 mDataSource.insertProfile(mProfile);
418 }
419 setResult(RESULT_OK, new Intent().putExtra(VpnProfileDataSource.KEY_ID, mProfile.getId()));
420 finish();
421 }
422 }
423
424 /**
425 * Verify the user input and display error messages.
426 * @return true if the input is valid
427 */
428 private boolean verifyInput()
429 {
430 boolean valid = true;
431 if (mGateway.getText().toString().trim().isEmpty())
432 {
433 mGatewayWrap.setError(getString(R.string.alert_text_no_input_gateway));
434 valid = false;
435 }
436 if (mVpnType.has(VpnTypeFeature.USER_PASS))
437 {
438 if (mUsername.getText().toString().trim().isEmpty())
439 {
440 mUsernameWrap.setError(getString(R.string.alert_text_no_input_username));
441 valid = false;
442 }
443 }
444 if (mVpnType.has(VpnTypeFeature.CERTIFICATE) && mUserCertEntry == null)
445 { /* let's show an error icon */
446 ((TextView)mSelectUserCert.findViewById(android.R.id.text1)).setError("");
447 valid = false;
448 }
449 if (!mCheckAuto.isChecked() && mCertEntry == null)
450 {
451 showCertificateAlert();
452 valid = false;
453 }
454 Integer mtu = getInteger(mMTU);
455 if (mtu != null && (mtu < MTU_MIN || mtu > MTU_MAX))
456 {
457 mMTUWrap.setError(String.format(getString(R.string.alert_text_out_of_range), MTU_MIN, MTU_MAX));
458 valid = false;
459 }
460 Integer port = getInteger(mPort);
461 if (port != null && (port < 1 || port > 65535))
462 {
463 mPortWrap.setError(String.format(getString(R.string.alert_text_out_of_range), 1, 65535));
464 valid = false;
465 }
466 return valid;
467 }
468
469 /**
470 * Update the profile object with the data entered by the user
471 */
472 private void updateProfileData()
473 {
474 /* the name is optional, we default to the gateway if none is given */
475 String name = mName.getText().toString().trim();
476 String gateway = mGateway.getText().toString().trim();
477 mProfile.setName(name.isEmpty() ? gateway : name);
478 mProfile.setGateway(gateway);
479 mProfile.setVpnType(mVpnType);
480 if (mVpnType.has(VpnTypeFeature.USER_PASS))
481 {
482 mProfile.setUsername(mUsername.getText().toString().trim());
483 String password = mPassword.getText().toString().trim();
484 password = password.isEmpty() ? null : password;
485 mProfile.setPassword(password);
486 }
487 if (mVpnType.has(VpnTypeFeature.CERTIFICATE))
488 {
489 mProfile.setUserCertificateAlias(mUserCertEntry.getAlias());
490 }
491 String certAlias = mCheckAuto.isChecked() ? null : mCertEntry.getAlias();
492 mProfile.setCertificateAlias(certAlias);
493 String remote_id = mRemoteId.getText().toString().trim();
494 mProfile.setRemoteId(remote_id.isEmpty() ? null : remote_id);
495 mProfile.setMTU(getInteger(mMTU));
496 mProfile.setPort(getInteger(mPort));
497 int st = 0;
498 st |= mBlockIPv4.isChecked() ? VpnProfile.SPLIT_TUNNELING_BLOCK_IPV4 : 0;
499 st |= mBlockIPv6.isChecked() ? VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6 : 0;
500 mProfile.setSplitTunneling(st == 0 ? null : st);
501 }
502
503 /**
504 * Load an existing profile if we got an ID
505 *
506 * @param savedInstanceState previously saved state
507 */
508 private void loadProfileData(Bundle savedInstanceState)
509 {
510 String useralias = null, alias = null;
511
512 getSupportActionBar().setTitle(R.string.add_profile);
513 if (mId != null && mId != 0)
514 {
515 mProfile = mDataSource.getVpnProfile(mId);
516 if (mProfile != null)
517 {
518 mName.setText(mProfile.getName());
519 mGateway.setText(mProfile.getGateway());
520 mVpnType = mProfile.getVpnType();
521 mUsername.setText(mProfile.getUsername());
522 mPassword.setText(mProfile.getPassword());
523 mRemoteId.setText(mProfile.getRemoteId());
524 mMTU.setText(mProfile.getMTU() != null ? mProfile.getMTU().toString() : null);
525 mPort.setText(mProfile.getPort() != null ? mProfile.getPort().toString() : null);
526 mBlockIPv4.setChecked(mProfile.getSplitTunneling() != null ? (mProfile.getSplitTunneling() & VpnProfile.SPLIT_TUNNELING_BLOCK_IPV4) != 0 : false);
527 mBlockIPv6.setChecked(mProfile.getSplitTunneling() != null ? (mProfile.getSplitTunneling() & VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6) != 0 : false);
528 useralias = mProfile.getUserCertificateAlias();
529 alias = mProfile.getCertificateAlias();
530 getSupportActionBar().setTitle(mProfile.getName());
531 }
532 else
533 {
534 Log.e(VpnProfileDetailActivity.class.getSimpleName(),
535 "VPN profile with id " + mId + " not found");
536 finish();
537 }
538 }
539
540 mSelectVpnType.setSelection(mVpnType.ordinal());
541
542 /* check if the user selected a user certificate previously */
543 useralias = savedInstanceState == null ? useralias: savedInstanceState.getString(VpnProfileDataSource.KEY_USER_CERTIFICATE);
544 if (useralias != null)
545 {
546 UserCertificateLoader loader = new UserCertificateLoader(this, useralias);
547 mUserCertLoading = useralias;
548 loader.execute();
549 }
550
551 /* check if the user selected a CA certificate previously */
552 alias = savedInstanceState == null ? alias : savedInstanceState.getString(VpnProfileDataSource.KEY_CERTIFICATE);
553 mCheckAuto.setChecked(alias == null);
554 if (alias != null)
555 {
556 X509Certificate certificate = TrustedCertificateManager.getInstance().getCACertificateFromAlias(alias);
557 if (certificate != null)
558 {
559 mCertEntry = new TrustedCertificateEntry(alias, certificate);
560 }
561 else
562 { /* previously selected certificate is not here anymore */
563 showCertificateAlert();
564 mCertEntry = null;
565 }
566 }
567 }
568
569 /**
570 * Get the integer value in the given text box or null if empty
571 *
572 * @param view text box (numeric entry assumed)
573 */
574 private Integer getInteger(EditText view)
575 {
576 String value = view.getText().toString().trim();
577 return value.isEmpty() ? null : Integer.valueOf(value);
578 }
579
580 private class SelectUserCertOnClickListener implements OnClickListener, KeyChainAliasCallback
581 {
582 @Override
583 public void onClick(View v)
584 {
585 String useralias = mUserCertEntry != null ? mUserCertEntry.getAlias() : null;
586 KeyChain.choosePrivateKeyAlias(VpnProfileDetailActivity.this, this, new String[] { "RSA" }, null, null, -1, useralias);
587 }
588
589 @Override
590 public void alias(final String alias)
591 {
592 if (alias != null)
593 { /* otherwise the dialog was canceled, the request denied */
594 try
595 {
596 final X509Certificate[] chain = KeyChain.getCertificateChain(VpnProfileDetailActivity.this, alias);
597 /* alias() is not called from our main thread */
598 runOnUiThread(new Runnable() {
599 @Override
600 public void run()
601 {
602 if (chain != null && chain.length > 0)
603 {
604 mUserCertEntry = new TrustedCertificateEntry(alias, chain[0]);
605 }
606 updateCredentialView();
607 }
608 });
609 }
610 catch (KeyChainException e)
611 {
612 e.printStackTrace();
613 }
614 catch (InterruptedException e)
615 {
616 e.printStackTrace();
617 }
618 }
619 }
620 }
621
622 /**
623 * Load the selected user certificate asynchronously. This cannot be done
624 * from the main thread as getCertificateChain() calls back to our main
625 * thread to bind to the KeyChain service resulting in a deadlock.
626 */
627 private class UserCertificateLoader extends AsyncTask<Void, Void, X509Certificate>
628 {
629 private final Context mContext;
630 private final String mAlias;
631
632 public UserCertificateLoader(Context context, String alias)
633 {
634 mContext = context;
635 mAlias = alias;
636 }
637
638 @Override
639 protected X509Certificate doInBackground(Void... params)
640 {
641 X509Certificate[] chain = null;
642 try
643 {
644 chain = KeyChain.getCertificateChain(mContext, mAlias);
645 }
646 catch (KeyChainException e)
647 {
648 e.printStackTrace();
649 }
650 catch (InterruptedException e)
651 {
652 e.printStackTrace();
653 }
654 if (chain != null && chain.length > 0)
655 {
656 return chain[0];
657 }
658 return null;
659 }
660
661 @Override
662 protected void onPostExecute(X509Certificate result)
663 {
664 if (result != null)
665 {
666 mUserCertEntry = new TrustedCertificateEntry(mAlias, result);
667 }
668 else
669 { /* previously selected certificate is not here anymore */
670 ((TextView)mSelectUserCert.findViewById(android.R.id.text1)).setError("");
671 mUserCertEntry = null;
672 }
673 mUserCertLoading = null;
674 updateCredentialView();
675 }
676 }
677
678 /**
679 * Dialog with notification message if EAP-TNC is used.
680 */
681 public static class TncNoticeDialog extends AppCompatDialogFragment
682 {
683 @Override
684 public Dialog onCreateDialog(Bundle savedInstanceState)
685 {
686 return new AlertDialog.Builder(getActivity())
687 .setTitle(R.string.tnc_notice_title)
688 .setMessage(Html.fromHtml(getString(R.string.tnc_notice_details)))
689 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
690 @Override
691 public void onClick(DialogInterface dialog, int id)
692 {
693 dialog.dismiss();
694 }
695 }).create();
696 }
697 }
698 }