Settings: revise VpnSettings.

Make the style closer to other settings.
Profiles are saved in KeyStore with optional account information.
Not adapt to IConnectivityManager yet.

Change-Id: I9d7a0c14b253a0b355499c5e558b0761fa24ea22
This commit is contained in:
Chia-chi Yeh
2011-06-26 19:17:14 -07:00
parent 827fde31e8
commit 310d619acb
6 changed files with 885 additions and 7 deletions

View File

@@ -0,0 +1,325 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.vpn2;
import com.android.settings.R;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.security.Credentials;
import android.security.KeyStore;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Spinner;
import android.widget.TextView;
class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListener {
private static final String DUMMY = "\r\r\r\r";
private static String getDummy(String secret) {
return secret.isEmpty() ? "" : DUMMY;
}
private static String getSecret(TextView dummy) {
String secret = dummy.getText().toString();
return DUMMY.equals(secret) ? "" : secret;
}
private final KeyStore mKeyStore = KeyStore.getInstance();
private final DialogInterface.OnClickListener mListener;
private final VpnProfile mProfile;
private boolean mEditing;
private View mView;
private TextView mName;
private Spinner mType;
private TextView mServer;
private TextView mUsername;
private TextView mPassword;
private TextView mDomains;
private TextView mRoutes;
private CheckBox mMppe;
private TextView mL2tpSecret;
private TextView mIpsecIdentifier;
private TextView mIpsecSecret;
private Spinner mIpsecUserCert;
private Spinner mIpsecCaCert;
private CheckBox mSaveLogin;
VpnDialog(Context context, DialogInterface.OnClickListener listener,
VpnProfile profile, boolean editing) {
super(context);
mListener = listener;
mProfile = profile;
mEditing = editing;
}
@Override
protected void onCreate(Bundle savedState) {
mView = getLayoutInflater().inflate(R.layout.vpn_dialog, null);
setView(mView);
setInverseBackgroundForced(true);
Context context = getContext();
// First, find out all the fields.
mName = (TextView) mView.findViewById(R.id.name);
mType = (Spinner) mView.findViewById(R.id.type);
mServer = (TextView) mView.findViewById(R.id.server);
mUsername = (TextView) mView.findViewById(R.id.username);
mPassword = (TextView) mView.findViewById(R.id.password);
mDomains = (TextView) mView.findViewById(R.id.domains);
mRoutes = (TextView) mView.findViewById(R.id.routes);
mMppe = (CheckBox) mView.findViewById(R.id.mppe);
mL2tpSecret = (TextView) mView.findViewById(R.id.l2tp_secret);
mIpsecIdentifier = (TextView) mView.findViewById(R.id.ipsec_identifier);
mIpsecSecret = (TextView) mView.findViewById(R.id.ipsec_secret);
mIpsecUserCert = (Spinner) mView.findViewById(R.id.ipsec_user_cert);
mIpsecCaCert = (Spinner) mView.findViewById(R.id.ipsec_ca_cert);
mSaveLogin = (CheckBox) mView.findViewById(R.id.save_login);
// Second, copy values from the profile.
mName.setText(mProfile.name);
mType.setSelection(mProfile.type);
mServer.setText(mProfile.server);
mUsername.setText(mProfile.username);
mPassword.setText(getDummy(mProfile.password));
mDomains.setText(mProfile.domains);
mRoutes.setText(mProfile.routes);
mMppe.setChecked(mProfile.mppe);
mL2tpSecret.setText(getDummy(mProfile.l2tpSecret));
mIpsecIdentifier.setText(mProfile.ipsecIdentifier);
mIpsecSecret.setText(getDummy(mProfile.ipsecSecret));
loadCertificates(mIpsecUserCert, Credentials.USER_CERTIFICATE,
0, mProfile.ipsecUserCert);
loadCertificates(mIpsecUserCert, Credentials.CA_CERTIFICATE,
R.string.vpn_no_ca_cert, mProfile.ipsecCaCert);
mSaveLogin.setChecked(mProfile.saveLogin);
// Third, add listeners to required fields.
mName.addTextChangedListener(this);
mType.setOnItemSelectedListener(this);
mServer.addTextChangedListener(this);
mUsername.addTextChangedListener(this);
mPassword.addTextChangedListener(this);
mIpsecSecret.addTextChangedListener(this);
mIpsecUserCert.setOnItemSelectedListener(this);
// Forth, determine to do editing or connecting.
boolean valid = validate(true);
mEditing = mEditing || !valid;
if (mEditing) {
setTitle(R.string.vpn_edit);
// Show common fields.
mView.findViewById(R.id.editor).setVisibility(View.VISIBLE);
// Show type-specific fields.
changeType(mProfile.type);
// Create a button to save the profile.
setButton(DialogInterface.BUTTON_POSITIVE,
context.getString(R.string.vpn_save), mListener);
} else {
setTitle(context.getString(R.string.vpn_connect_to, mProfile.name));
// Not editing, just show username and password.
mView.findViewById(R.id.login).setVisibility(View.VISIBLE);
// Create a button to connect the network.
setButton(DialogInterface.BUTTON_POSITIVE,
context.getString(R.string.vpn_connect), mListener);
}
// Always provide a cancel button.
setButton(DialogInterface.BUTTON_NEGATIVE,
context.getString(R.string.vpn_cancel), mListener);
// Let AlertDialog create everything.
super.onCreate(null);
// Disable the action button if necessary.
getButton(DialogInterface.BUTTON_POSITIVE)
.setEnabled(mEditing ? valid : validate(false));
}
@Override
public void afterTextChanged(Editable field) {
getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validate(mEditing));
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent == mType) {
changeType(position);
}
getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validate(false));
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
private void changeType(int type) {
// First, hide everything.
mMppe.setVisibility(View.GONE);
mView.findViewById(R.id.l2tp).setVisibility(View.GONE);
mView.findViewById(R.id.ipsec_psk).setVisibility(View.GONE);
mView.findViewById(R.id.ipsec_user).setVisibility(View.GONE);
mView.findViewById(R.id.ipsec_ca).setVisibility(View.GONE);
// Then, unhide type-specific fields.
switch (type) {
case VpnProfile.TYPE_PPTP:
mMppe.setVisibility(View.VISIBLE);
break;
case VpnProfile.TYPE_L2TP_IPSEC_PSK:
mView.findViewById(R.id.l2tp).setVisibility(View.VISIBLE);
// fall through
case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
mView.findViewById(R.id.ipsec_psk).setVisibility(View.VISIBLE);
break;
case VpnProfile.TYPE_L2TP_IPSEC_RSA:
mView.findViewById(R.id.l2tp).setVisibility(View.VISIBLE);
// fall through
case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
mView.findViewById(R.id.ipsec_ca).setVisibility(View.VISIBLE);
// fall through
case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
mView.findViewById(R.id.ipsec_user).setVisibility(View.VISIBLE);
break;
}
}
private boolean validate(boolean editing) {
if (!editing) {
return mUsername.getText().length() != 0 && mPassword.getText().length() != 0;
}
if (mName.getText().length() == 0 || mServer.getText().length() == 0) {
return false;
}
switch (mType.getSelectedItemPosition()) {
case VpnProfile.TYPE_PPTP:
return true;
case VpnProfile.TYPE_L2TP_IPSEC_PSK:
case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
return mIpsecSecret.getText().length() != 0;
case VpnProfile.TYPE_L2TP_IPSEC_RSA:
case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
return mIpsecUserCert.getSelectedItemPosition() != 0;
}
return false;
}
private void loadCertificates(Spinner spinner, String prefix, int firstId, String selected) {
Context context = getContext();
String first = (firstId == 0) ? "" : context.getString(firstId);
String[] certs = mKeyStore.saw(prefix);
if (certs == null || certs.length == 0) {
certs = new String[] {first};
} else {
String[] array = new String[certs.length + 1];
array[0] = first;
System.arraycopy(certs, 0, array, 1, certs.length);
certs = array;
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
context, android.R.layout.simple_spinner_item, certs);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
for (int i = 1; i < certs.length; ++i) {
if (certs[i].equals(selected)) {
spinner.setSelection(i);
break;
}
}
}
boolean isEditing() {
return mEditing;
}
VpnProfile getProfile() {
// First, save common fields.
VpnProfile profile = new VpnProfile(mProfile.key);
profile.name = mName.getText().toString();
profile.type = mType.getSelectedItemPosition();
profile.server = mServer.getText().toString().trim();
profile.username = mUsername.getText().toString();
profile.password = getSecret(mPassword);
profile.domains = mDomains.getText().toString().trim();
profile.routes = mRoutes.getText().toString().trim();
// Then, save type-specific fields.
switch (profile.type) {
case VpnProfile.TYPE_PPTP:
profile.mppe = mMppe.isChecked();
break;
case VpnProfile.TYPE_L2TP_IPSEC_PSK:
profile.l2tpSecret = getSecret(mL2tpSecret);
// fall through
case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
profile.ipsecSecret = getSecret(mIpsecSecret);
break;
case VpnProfile.TYPE_L2TP_IPSEC_RSA:
profile.l2tpSecret = getSecret(mL2tpSecret);
// fall through
case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
if (mIpsecCaCert.getSelectedItemPosition() != 0) {
profile.ipsecCaCert = (String) mIpsecCaCert.getSelectedItem();
}
// fall through
case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
if (mIpsecUserCert.getSelectedItemPosition() != 0) {
profile.ipsecUserCert = (String) mIpsecUserCert.getSelectedItem();
}
break;
}
profile.saveLogin = mSaveLogin.isChecked();
return profile;
}
}