Added new UI to select a specific CA certificate

With this change there is no need to wait for all certificates being loaded
anymore (this happens only when the user opens the selection activity).
This commit is contained in:
Tobias Brunner
2012-08-14 12:01:41 +02:00
parent cb431e12da
commit 4db2d6336e
5 changed files with 140 additions and 32 deletions
@@ -91,6 +91,33 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/profile_ca_auto_label" /> android:text="@string/profile_ca_auto_label" />
<RelativeLayout
android:id="@+id/select_certificate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:background="?android:attr/selectableItemBackground"
android:padding="10dp" >
<TextView
android:id="@+id/select_certificate_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/profile_ca_select_certificate_label" />
<TextView
android:id="@+id/select_certificate_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/select_certificate_title"
android:layout_alignLeft="@id/select_certificate_title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:text="@string/profile_ca_select_certificate" />
</RelativeLayout>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>
@@ -51,6 +51,8 @@
<string name="profile_password_hint">(anfordern wenn benötigt)</string> <string name="profile_password_hint">(anfordern wenn benötigt)</string>
<string name="profile_ca_label">CA-Zertifikat:</string> <string name="profile_ca_label">CA-Zertifikat:</string>
<string name="profile_ca_auto_label">Automatisch wählen</string> <string name="profile_ca_auto_label">Automatisch wählen</string>
<string name="profile_ca_select_certificate_label">CA-Zertifikat auswählen</string>
<string name="profile_ca_select_certificate">Wählen Sie ein bestimmtes CA-Zertifikat</string>
<!-- Warnings/Notifications in the details view --> <!-- Warnings/Notifications in the details view -->
<string name="alert_text_no_input_gateway">Bitte geben Sie hier die Gateway-Adresse ein</string> <string name="alert_text_no_input_gateway">Bitte geben Sie hier die Gateway-Adresse ein</string>
<string name="alert_text_no_input_username">Bitte geben Sie hier Ihren Benutzernamen ein</string> <string name="alert_text_no_input_username">Bitte geben Sie hier Ihren Benutzernamen ein</string>
@@ -51,6 +51,8 @@
<string name="profile_password_hint">(prompt when needed)</string> <string name="profile_password_hint">(prompt when needed)</string>
<string name="profile_ca_label">CA certificate:</string> <string name="profile_ca_label">CA certificate:</string>
<string name="profile_ca_auto_label">Select automatically</string> <string name="profile_ca_auto_label">Select automatically</string>
<string name="profile_ca_select_certificate_label">Select CA certificate</string>
<string name="profile_ca_select_certificate">Select a specific CA certificate</string>
<!-- Warnings/Notifications in the details view --> <!-- Warnings/Notifications in the details view -->
<string name="alert_text_no_input_gateway">Please enter the gateway address here</string> <string name="alert_text_no_input_gateway">Please enter the gateway address here</string>
<string name="alert_text_no_input_username">Please enter your username here</string> <string name="alert_text_no_input_username">Please enter your username here</string>
@@ -16,16 +16,19 @@
package org.strongswan.android.ui; package org.strongswan.android.ui;
import org.strongswan.android.R; import org.strongswan.android.R;
import org.strongswan.android.data.TrustedCertificateEntry;
import org.strongswan.android.data.VpnProfileDataSource;
import android.app.ActionBar; import android.app.ActionBar;
import android.app.ActionBar.Tab; import android.app.ActionBar.Tab;
import android.app.Activity; import android.app.Activity;
import android.app.Fragment; import android.app.Fragment;
import android.app.FragmentTransaction; import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.MenuItem; import android.view.MenuItem;
public class TrustedCertificatesActivity extends Activity public class TrustedCertificatesActivity extends Activity implements TrustedCertificateListFragment.OnTrustedCertificateSelectedListener
{ {
@Override @Override
public void onCreate(Bundle savedInstanceState) public void onCreate(Bundle savedInstanceState)
@@ -71,6 +74,16 @@ public class TrustedCertificatesActivity extends Activity
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@Override
public void onTrustedCertificateSelected(TrustedCertificateEntry selected)
{
/* the user selected a certificate, return to calling activity */
Intent intent = new Intent();
intent.putExtra(VpnProfileDataSource.KEY_CERTIFICATE, selected.getAlias());
setResult(Activity.RESULT_OK, intent);
finish();
}
public static class TrustedCertificatesTabListener implements ActionBar.TabListener public static class TrustedCertificatesTabListener implements ActionBar.TabListener
{ {
private final String mTag; private final String mTag;
@@ -17,7 +17,10 @@
package org.strongswan.android.ui; package org.strongswan.android.ui;
import java.security.cert.X509Certificate;
import org.strongswan.android.R; import org.strongswan.android.R;
import org.strongswan.android.data.TrustedCertificateEntry;
import org.strongswan.android.data.VpnProfile; import org.strongswan.android.data.VpnProfile;
import org.strongswan.android.data.VpnProfileDataSource; import org.strongswan.android.data.VpnProfileDataSource;
import org.strongswan.android.logic.TrustedCertificateManager; import org.strongswan.android.logic.TrustedCertificateManager;
@@ -26,37 +29,42 @@ import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.Window; import android.view.View.OnClickListener;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText; import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class VpnProfileDetailActivity extends Activity public class VpnProfileDetailActivity extends Activity
{ {
private static final int SELECT_TRUSTED_CERTIFICATE = 0;
private VpnProfileDataSource mDataSource; private VpnProfileDataSource mDataSource;
private Long mId; private Long mId;
private TrustedCertificateEntry mCertEntry;
private VpnProfile mProfile; private VpnProfile mProfile;
private boolean mCertsLoaded;
private String mCertAlias;
private EditText mName; private EditText mName;
private EditText mGateway; private EditText mGateway;
private EditText mUsername; private EditText mUsername;
private EditText mPassword; private EditText mPassword;
private CheckBox mCheckAuto; private CheckBox mCheckAuto;
private RelativeLayout mSelectCert;
private TextView mCertTitle;
private TextView mCertSubtitle;
@Override @Override
public void onCreate(Bundle savedInstanceState) public void onCreate(Bundle savedInstanceState)
{ {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
/* the title is set when we load the profile, if any */ /* the title is set when we load the profile, if any */
getActionBar().setDisplayHomeAsUpEnabled(true); getActionBar().setDisplayHomeAsUpEnabled(true);
@@ -72,12 +80,24 @@ public class VpnProfileDetailActivity extends Activity
mUsername = (EditText)findViewById(R.id.username); mUsername = (EditText)findViewById(R.id.username);
mCheckAuto = (CheckBox)findViewById(R.id.ca_auto); mCheckAuto = (CheckBox)findViewById(R.id.ca_auto);
mSelectCert = (RelativeLayout)findViewById(R.id.select_certificate);
mCertTitle = (TextView)findViewById(R.id.select_certificate_title);
mCertSubtitle = (TextView)findViewById(R.id.select_certificate_subtitle);
mCheckAuto.setOnCheckedChangeListener(new OnCheckedChangeListener() { mCheckAuto.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{ {
updateCertificateSelector();
}
});
mSelectCert.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v)
{
Intent intent = new Intent(VpnProfileDetailActivity.this, TrustedCertificatesActivity.class);
startActivityForResult(intent, SELECT_TRUSTED_CERTIFICATE);
} }
}); });
@@ -88,9 +108,9 @@ public class VpnProfileDetailActivity extends Activity
mId = extras == null ? null : extras.getLong(VpnProfileDataSource.KEY_ID); mId = extras == null ? null : extras.getLong(VpnProfileDataSource.KEY_ID);
} }
loadProfileData(); loadProfileData(savedInstanceState);
new CertificateLoadTask().execute(); updateCertificateSelector();
} }
@Override @Override
@@ -108,6 +128,10 @@ public class VpnProfileDetailActivity extends Activity
{ {
outState.putLong(VpnProfileDataSource.KEY_ID, mId); outState.putLong(VpnProfileDataSource.KEY_ID, mId);
} }
if (mCertEntry != null)
{
outState.putString(VpnProfileDataSource.KEY_CERTIFICATE, mCertEntry.getAlias());
}
} }
@Override @Override
@@ -135,6 +159,25 @@ public class VpnProfileDetailActivity extends Activity
} }
} }
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch (requestCode)
{
case SELECT_TRUSTED_CERTIFICATE:
if (resultCode == RESULT_OK)
{
String alias = data.getStringExtra(VpnProfileDataSource.KEY_CERTIFICATE);
X509Certificate certificate = TrustedCertificateManager.getInstance().getCACertificateFromAlias(alias);
mCertEntry = certificate == null ? null : new TrustedCertificateEntry(alias, certificate);
updateCertificateSelector();
}
break;
default:
super.onActivityResult(requestCode, resultCode, data);
}
}
/** /**
* Show an alert in case the previously selected certificate is not found anymore * Show an alert in case the previously selected certificate is not found anymore
* or the user did not select a certificate in the spinner. * or the user did not select a certificate in the spinner.
@@ -155,32 +198,31 @@ public class VpnProfileDetailActivity extends Activity
} }
/** /**
* Asynchronously executed task which confirms that the certificates are loaded. * Update the CA certificate selection UI depending on whether the
* They are loaded from the main Activity already but might not be ready yet, or * certificate should be automatically selected or not.
* unloaded again.
*
* Once loaded the CA certificate spinner and checkboxes are updated
* accordingly.
*/ */
private class CertificateLoadTask extends AsyncTask<Void, Void, TrustedCertificateManager> private void updateCertificateSelector()
{ {
@Override if (!mCheckAuto.isChecked())
protected void onPreExecute()
{ {
setProgressBarIndeterminateVisibility(true); mSelectCert.setEnabled(true);
} mSelectCert.setVisibility(View.VISIBLE);
@Override if (mCertEntry != null)
protected TrustedCertificateManager doInBackground(Void... params) {
{ mCertTitle.setText(mCertEntry.getSubjectPrimary());
return TrustedCertificateManager.getInstance().load(); mCertSubtitle.setText(mCertEntry.getSubjectSecondary());
}
else
{
mCertTitle.setText(R.string.profile_ca_select_certificate_label);
mCertSubtitle.setText(R.string.profile_ca_select_certificate);
}
} }
else
@Override
protected void onPostExecute(TrustedCertificateManager result)
{ {
setProgressBarIndeterminateVisibility(false); mSelectCert.setEnabled(false);
mCertsLoaded = true; mSelectCert.setVisibility(View.GONE);
} }
} }
@@ -225,7 +267,7 @@ public class VpnProfileDetailActivity extends Activity
mUsername.setError(getString(R.string.alert_text_no_input_username)); mUsername.setError(getString(R.string.alert_text_no_input_username));
valid = false; valid = false;
} }
if (!mCheckAuto.isChecked()) if (!mCheckAuto.isChecked() && mCertEntry == null)
{ {
showCertificateAlert(); showCertificateAlert();
valid = false; valid = false;
@@ -247,13 +289,19 @@ public class VpnProfileDetailActivity extends Activity
String password = mPassword.getText().toString().trim(); String password = mPassword.getText().toString().trim();
password = password.isEmpty() ? null : password; password = password.isEmpty() ? null : password;
mProfile.setPassword(password); mProfile.setPassword(password);
String certAlias = mCheckAuto.isChecked() ? null : mCertEntry.getAlias();
mProfile.setCertificateAlias(certAlias);
} }
/** /**
* Load an existing profile if we got an ID * Load an existing profile if we got an ID
*
* @param savedInstanceState previously saved state
*/ */
private void loadProfileData() private void loadProfileData(Bundle savedInstanceState)
{ {
String alias = null;
getActionBar().setTitle(R.string.add_profile); getActionBar().setTitle(R.string.add_profile);
if (mId != null) if (mId != null)
{ {
@@ -264,7 +312,7 @@ public class VpnProfileDetailActivity extends Activity
mGateway.setText(mProfile.getGateway()); mGateway.setText(mProfile.getGateway());
mUsername.setText(mProfile.getUsername()); mUsername.setText(mProfile.getUsername());
mPassword.setText(mProfile.getPassword()); mPassword.setText(mProfile.getPassword());
mCertAlias = mProfile.getCertificateAlias(); alias = mProfile.getCertificateAlias();
getActionBar().setTitle(mProfile.getName()); getActionBar().setTitle(mProfile.getName());
} }
else else
@@ -274,6 +322,22 @@ public class VpnProfileDetailActivity extends Activity
finish(); finish();
} }
} }
mCheckAuto.setChecked(mCertAlias == null);
/* check if the user selected a certificate previously */
alias = savedInstanceState == null ? alias : savedInstanceState.getString(VpnProfileDataSource.KEY_CERTIFICATE);
mCheckAuto.setChecked(alias == null);
if (alias != null)
{
X509Certificate certificate = TrustedCertificateManager.getInstance().getCACertificateFromAlias(alias);
if (certificate != null)
{
mCertEntry = new TrustedCertificateEntry(alias, certificate);
}
else
{ /* previously selected certificate is not here anymore */
showCertificateAlert();
mCertEntry = null;
}
}
} }
} }