summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
authorHung-ying Tyan <tyanh@google.com>2009-07-06 17:26:34 +0800
committerHung-ying Tyan <tyanh@google.com>2009-07-06 18:47:47 +0800
commit0a59b500147cc038541f6f2897de7e28c15a12c1 (patch)
treef5d44650a99de7e5bc86933e8764d3d51c970da3 /src/com
parenteb7836f11ec4e9753db7c6ecd9414e153bb7bdbe (diff)
downloadpackages_apps_settings-0a59b500147cc038541f6f2897de7e28c15a12c1.zip
packages_apps_settings-0a59b500147cc038541f6f2897de7e28c15a12c1.tar.gz
packages_apps_settings-0a59b500147cc038541f6f2897de7e28c15a12c1.tar.bz2
Integrate VPN with new keystore and misc fixes.
* Changes + Pass intent to keystore when needed and hooks to resume from it. + Generate random, unique ID for profile instead of base64 from its name. + Add VPN to "Wirless controls" description. + Add credential storage to "Security & location" description. + More hints to set password and unlock dialogs in credential storage settings for actions that come from other processes. + Sort VPN profiles according to the names. + Replace Keystore with CertTool in L2tpIpsecEditor
Diffstat (limited to 'src/com')
-rw-r--r--src/com/android/settings/SecuritySettings.java33
-rw-r--r--src/com/android/settings/vpn/L2tpEditor.java6
-rw-r--r--src/com/android/settings/vpn/L2tpIpsecEditor.java6
-rw-r--r--src/com/android/settings/vpn/L2tpIpsecPskEditor.java7
-rw-r--r--src/com/android/settings/vpn/Util.java6
-rw-r--r--src/com/android/settings/vpn/VpnEditor.java7
-rw-r--r--src/com/android/settings/vpn/VpnProfileEditor.java7
-rw-r--r--src/com/android/settings/vpn/VpnSettings.java189
8 files changed, 203 insertions, 58 deletions
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 4e77d6b..73578c7 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -577,8 +577,7 @@ public class SecuritySettings extends PreferenceActivity implements
: R.string.cstor_password_error);
if (count <= 3) {
if (count == 1) {
- v.setText(getString(
- R.string.cstor_password_error_reset_warning));
+ v.setText(R.string.cstor_password_error_reset_warning);
} else {
String format = getString(
R.string.cstor_password_error_reset_warning_plural);
@@ -691,11 +690,15 @@ public class SecuritySettings extends PreferenceActivity implements
return v;
}
- private void hideError() {
- View v = mView.findViewById(R.id.cstor_error);
+ private void hide(int viewId) {
+ View v = mView.findViewById(viewId);
if (v != null) v.setVisibility(View.GONE);
}
+ private void hideError() {
+ hide(R.id.cstor_error);
+ }
+
private String getText(int viewId) {
return ((TextView) mView.findViewById(viewId)).getText().toString();
}
@@ -705,6 +708,11 @@ public class SecuritySettings extends PreferenceActivity implements
if (v != null) v.setText(text);
}
+ private void setText(int viewId, int textId) {
+ TextView v = (TextView) mView.findViewById(viewId);
+ if (v != null) v.setText(textId);
+ }
+
private void enablePreferences(boolean enabled) {
mAccessCheckBox.setEnabled(enabled);
mResetButton.setEnabled(enabled);
@@ -773,6 +781,12 @@ public class SecuritySettings extends PreferenceActivity implements
R.layout.cstor_unlock_dialog_view, null);
hideError();
+ // show extra hint only when the action comes from outside
+ if ((mSpecialIntent == null)
+ && (mCstorAddCredentialHelper == null)) {
+ hide(R.id.cstor_access_dialog_hint_from_action);
+ }
+
Dialog d = new AlertDialog.Builder(SecuritySettings.this)
.setView(mView)
.setTitle(R.string.cstor_access_dialog_title)
@@ -790,6 +804,13 @@ public class SecuritySettings extends PreferenceActivity implements
R.layout.cstor_set_password_dialog_view, null);
hideError();
+ // show extra hint only when the action comes from outside
+ if ((mSpecialIntent != null)
+ || (mCstorAddCredentialHelper != null)) {
+ setText(R.id.cstor_first_time_hint,
+ R.string.cstor_first_time_hint_from_action);
+ }
+
switch (id) {
case CSTOR_INIT_DIALOG:
mView.findViewById(R.id.cstor_old_password_block)
@@ -835,9 +856,9 @@ public class SecuritySettings extends PreferenceActivity implements
hideError();
setText(R.id.cstor_credential_name_title,
- getString(R.string.cstor_credential_name));
+ R.string.cstor_credential_name);
setText(R.id.cstor_credential_info_title,
- getString(R.string.cstor_credential_info));
+ R.string.cstor_credential_info);
setText(R.id.cstor_credential_info,
mCstorAddCredentialHelper.getDescription().toString());
diff --git a/src/com/android/settings/vpn/L2tpEditor.java b/src/com/android/settings/vpn/L2tpEditor.java
index 88a1142..c518dec 100644
--- a/src/com/android/settings/vpn/L2tpEditor.java
+++ b/src/com/android/settings/vpn/L2tpEditor.java
@@ -60,12 +60,6 @@ class L2tpEditor extends VpnProfileEditor {
: validate(mSecretString, R.string.vpn_l2tp_secret));
}
- @Override
- public void saveSecrets(String originalProfileName) {
- L2tpProfile profile = (L2tpProfile) getProfile();
- // TODO: fill up the implementation after keystore is available
- }
-
private Preference createSecretPreference(Context c) {
final L2tpProfile profile = (L2tpProfile) getProfile();
CheckBoxPreference secret = mSecret = new CheckBoxPreference(c);
diff --git a/src/com/android/settings/vpn/L2tpIpsecEditor.java b/src/com/android/settings/vpn/L2tpIpsecEditor.java
index e79760c..b6b244f 100644
--- a/src/com/android/settings/vpn/L2tpIpsecEditor.java
+++ b/src/com/android/settings/vpn/L2tpIpsecEditor.java
@@ -24,7 +24,7 @@ import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceGroup;
-import android.security.Keystore;
+import android.security.CertTool;
import android.text.TextUtils;
/**
@@ -67,7 +67,7 @@ class L2tpIpsecEditor extends L2tpEditor {
mUserCertificate = createListPreference(c,
R.string.vpn_user_certificate_title,
mProfile.getUserCertificate(),
- Keystore.getInstance().getAllUserCertificateKeys(),
+ CertTool.getInstance().getAllUserCertificateKeys(),
new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(
Preference pref, Object newValue) {
@@ -86,7 +86,7 @@ class L2tpIpsecEditor extends L2tpEditor {
mCaCertificate = createListPreference(c,
R.string.vpn_ca_certificate_title,
mProfile.getCaCertificate(),
- Keystore.getInstance().getAllCaCertificateKeys(),
+ CertTool.getInstance().getAllCaCertificateKeys(),
new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(
Preference pref, Object newValue) {
diff --git a/src/com/android/settings/vpn/L2tpIpsecPskEditor.java b/src/com/android/settings/vpn/L2tpIpsecPskEditor.java
index 9c1d02c..fb67c98 100644
--- a/src/com/android/settings/vpn/L2tpIpsecPskEditor.java
+++ b/src/com/android/settings/vpn/L2tpIpsecPskEditor.java
@@ -50,13 +50,6 @@ class L2tpIpsecPskEditor extends L2tpEditor {
: validate(mPresharedKey, R.string.vpn_ipsec_presharedkey));
}
- @Override
- public void saveSecrets(String originalProfileName) {
- L2tpIpsecPskProfile profile = (L2tpIpsecPskProfile) getProfile();
- profile.getPresharedKey();
- // TODO: fill up the implementation after keystore is available
- }
-
private Preference createPresharedKeyPreference(Context c) {
final L2tpIpsecPskProfile profile = (L2tpIpsecPskProfile) getProfile();
mPresharedKey = createSecretPreference(c,
diff --git a/src/com/android/settings/vpn/Util.java b/src/com/android/settings/vpn/Util.java
index e4316fd..a37049d 100644
--- a/src/com/android/settings/vpn/Util.java
+++ b/src/com/android/settings/vpn/Util.java
@@ -23,8 +23,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.widget.Toast;
-import org.apache.commons.codec.binary.Base64;
-
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -59,10 +57,6 @@ class Util {
createErrorDialog(c, message, listener).show();
}
- static String base64Encode(byte[] bytes) {
- return new String(Base64.encodeBase64(bytes));
- }
-
static void deleteFile(String path) {
deleteFile(new File(path));
}
diff --git a/src/com/android/settings/vpn/VpnEditor.java b/src/com/android/settings/vpn/VpnEditor.java
index e33ce55..1d419ea 100644
--- a/src/com/android/settings/vpn/VpnEditor.java
+++ b/src/com/android/settings/vpn/VpnEditor.java
@@ -46,7 +46,6 @@ public class VpnEditor extends PreferenceActivity {
private VpnProfileEditor mProfileEditor;
private boolean mAddingProfile;
- private String mOriginalProfileName;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -54,9 +53,6 @@ public class VpnEditor extends PreferenceActivity {
VpnProfile p = (VpnProfile) ((savedInstanceState == null)
? getIntent().getParcelableExtra(VpnSettings.KEY_VPN_PROFILE)
: savedInstanceState.getParcelable(KEY_PROFILE));
- mOriginalProfileName = (savedInstanceState == null)
- ? p.getName()
- : savedInstanceState.getString(KEY_ORIGINAL_PROFILE_NAME);
mProfileEditor = getEditor(p);
mAddingProfile = TextUtils.isEmpty(p.getName());
@@ -71,7 +67,6 @@ public class VpnEditor extends PreferenceActivity {
if (mProfileEditor == null) return;
outState.putParcelable(KEY_PROFILE, getProfile());
- outState.putString(KEY_ORIGINAL_PROFILE_NAME, mOriginalProfileName);
}
@Override
@@ -126,13 +121,11 @@ public class VpnEditor extends PreferenceActivity {
return false;
}
- mProfileEditor.saveSecrets(mOriginalProfileName);
setResult(getProfile());
return true;
}
private void setResult(VpnProfile p) {
- p.setId(Util.base64Encode(p.getName().getBytes()));
Intent intent = new Intent(this, VpnSettings.class);
intent.putExtra(VpnSettings.KEY_VPN_PROFILE, (Parcelable) p);
setResult(RESULT_OK, intent);
diff --git a/src/com/android/settings/vpn/VpnProfileEditor.java b/src/com/android/settings/vpn/VpnProfileEditor.java
index b679bcb..a708a8c 100644
--- a/src/com/android/settings/vpn/VpnProfileEditor.java
+++ b/src/com/android/settings/vpn/VpnProfileEditor.java
@@ -92,13 +92,6 @@ class VpnProfileEditor {
}
/**
- * Saves the secrets in this profile.
- * @param originalProfileName the original profile name
- */
- public void saveSecrets(String originalProfileName) {
- }
-
- /**
* Creates a preference for users to input domain suffices.
*/
protected EditTextPreference createDomainSufficesPreference(Context c) {
diff --git a/src/com/android/settings/vpn/VpnSettings.java b/src/com/android/settings/vpn/VpnSettings.java
index bbbe9b9..e429f9f 100644
--- a/src/com/android/settings/vpn/VpnSettings.java
+++ b/src/com/android/settings/vpn/VpnSettings.java
@@ -17,6 +17,7 @@
package com.android.settings.vpn;
import com.android.settings.R;
+import com.android.settings.SecuritySettings;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -24,6 +25,8 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.net.vpn.L2tpIpsecPskProfile;
+import android.net.vpn.L2tpProfile;
import android.net.vpn.VpnManager;
import android.net.vpn.VpnProfile;
import android.net.vpn.VpnState;
@@ -38,6 +41,7 @@ import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.preference.Preference.OnPreferenceClickListener;
+import android.security.Keystore;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
@@ -54,8 +58,8 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -113,6 +117,9 @@ public class VpnSettings extends PreferenceActivity implements
private VpnProfileActor mConnectingActor;
private boolean mStateSaved = false;
+ // states saved for unlocking keystore
+ private Runnable mUnlockAction;
+
private VpnManager mVpnManager = new VpnManager(this);
private ConnectivityReceiver mConnectivityReceiver =
@@ -169,6 +176,12 @@ public class VpnSettings extends PreferenceActivity implements
public void onResume() {
super.onResume();
mStatusChecker.onResume();
+
+ if ((mUnlockAction != null) && isKeystoreUnlocked()) {
+ Runnable action = mUnlockAction;
+ mUnlockAction = null;
+ runOnUiThread(action);
+ }
}
@Override
@@ -279,9 +292,9 @@ public class VpnSettings extends PreferenceActivity implements
}
@Override
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
- int index = mIndexOfEditedProfile;
+ protected void onActivityResult(final int requestCode, final int resultCode,
+ final Intent data) {
+ final int index = mIndexOfEditedProfile;
mIndexOfEditedProfile = -1;
if ((resultCode == RESULT_CANCELED) || (data == null)) {
@@ -312,6 +325,16 @@ public class VpnSettings extends PreferenceActivity implements
return;
}
+ if (needKeystoreToSave(p)) {
+ Runnable action = new Runnable() {
+ public void run() {
+ mIndexOfEditedProfile = index;
+ onActivityResult(requestCode, resultCode, data);
+ }
+ };
+ if (!unlockKeystore(p, action)) return;
+ }
+
try {
if ((index < 0) || (index >= mVpnProfileList.size())) {
addProfile(p);
@@ -414,7 +437,27 @@ public class VpnSettings extends PreferenceActivity implements
.show();
}
+ // Randomly generates an ID for the profile.
+ // The ID is unique and only set once when the profile is created.
+ private void setProfileId(VpnProfile profile) {
+ String id;
+
+ while (true) {
+ id = String.valueOf(Math.abs(
+ Double.doubleToLongBits(Math.random())));
+ if (id.length() >= 8) break;
+ }
+ for (VpnProfile p : mVpnProfileList) {
+ if (p.getId().equals(id)) {
+ setProfileId(profile);
+ return;
+ }
+ }
+ profile.setId(id);
+ }
+
private void addProfile(VpnProfile p) throws IOException {
+ setProfileId(p);
saveProfileToStorage(p);
mVpnProfileList.add(p);
addPreferenceFor(p);
@@ -445,8 +488,11 @@ public class VpnSettings extends PreferenceActivity implements
throw new RuntimeException("inconsistent state!");
}
- // TODO: call saveSecret(String) after keystore is available
+ p.setId(oldProfile.getId());
+
+ processSecrets(p);
+ // TODO: remove copyFiles once the setId() code propagates.
// Copy config files and remove the old ones if they are in different
// directories.
if (Util.copyFiles(getProfileDir(oldProfile), getProfileDir(p))) {
@@ -463,25 +509,93 @@ public class VpnSettings extends PreferenceActivity implements
startActivityForResult(intent, REQUEST_SELECT_VPN_TYPE);
}
- private void startVpnEditor(VpnProfile profile) {
+ private boolean isKeystoreUnlocked() {
+ return (Keystore.getInstance().getState() == Keystore.UNLOCKED);
+ }
+
+
+ // Returns true if the profile needs to access keystore
+ private boolean needKeystoreToSave(VpnProfile p) {
+ return needKeystoreToConnect(p);
+ }
+
+ // Returns true if the profile needs to access keystore
+ private boolean needKeystoreToEdit(VpnProfile p) {
+ switch (p.getType()) {
+ case L2TP_IPSEC:
+ case L2TP_IPSEC_PSK:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ // Returns true if the profile needs to access keystore
+ private boolean needKeystoreToConnect(VpnProfile p) {
+ switch (p.getType()) {
+ case L2TP_IPSEC:
+ case L2TP_IPSEC_PSK:
+ return true;
+
+ case L2TP:
+ return ((L2tpProfile) p).isSecretEnabled();
+
+ default:
+ return false;
+ }
+ }
+
+ // Returns true if keystore is unlocked or keystore is not a concern
+ private boolean unlockKeystore(VpnProfile p, Runnable action) {
+ if (isKeystoreUnlocked()) return true;
+ mUnlockAction = action;
+ startActivity(
+ new Intent(SecuritySettings.ACTION_UNLOCK_CREDENTIAL_STORAGE));
+ return false;
+ }
+
+ private void startVpnEditor(final VpnProfile profile) {
+ if (needKeystoreToEdit(profile)) {
+ Runnable action = new Runnable() {
+ public void run() {
+ startVpnEditor(profile);
+ }
+ };
+ if (!unlockKeystore(profile, action)) return;
+ }
+
Intent intent = new Intent(this, VpnEditor.class);
intent.putExtra(KEY_VPN_PROFILE, (Parcelable) profile);
startActivityForResult(intent, REQUEST_ADD_OR_EDIT_PROFILE);
}
+ private synchronized void connect(final VpnProfile p) {
+ if (needKeystoreToConnect(p)) {
+ Runnable action = new Runnable() {
+ public void run() {
+ connect(p);
+ }
+ };
+ if (!unlockKeystore(p, action)) return;
+ }
+
+ mConnectingActor = getActor(p);
+ if (mConnectingActor.isConnectDialogNeeded()) {
+ removeDialog(DIALOG_CONNECT);
+ showDialog(DIALOG_CONNECT);
+ } else {
+ changeState(p, VpnState.CONNECTING);
+ mConnectingActor.connect(null);
+ }
+ }
+
// Do connect or disconnect based on the current state.
private synchronized void connectOrDisconnect(VpnProfile p) {
VpnPreference pref = mVpnPreferenceMap.get(p.getName());
switch (p.getState()) {
case IDLE:
- mConnectingActor = getActor(p);
- if (mConnectingActor.isConnectDialogNeeded()) {
- removeDialog(DIALOG_CONNECT);
- showDialog(DIALOG_CONNECT);
- } else {
- changeState(p, VpnState.CONNECTING);
- mConnectingActor.connect(null);
- }
+ connect(p);
break;
case CONNECTING:
@@ -601,7 +715,6 @@ public class VpnSettings extends PreferenceActivity implements
File root = new File(PROFILES_ROOT);
String[] dirs = root.list();
if (dirs == null) return;
- Arrays.sort(dirs);
for (String dir : dirs) {
File f = new File(new File(root, dir), PROFILE_OBJ_FILE);
if (!f.exists()) continue;
@@ -611,11 +724,21 @@ public class VpnSettings extends PreferenceActivity implements
if (!checkIdConsistency(dir, p)) continue;
mVpnProfileList.add(p);
- addPreferenceFor(p);
} catch (IOException e) {
Log.e(TAG, "retrieveVpnListFromStorage()", e);
}
}
+ Collections.sort(mVpnProfileList, new Comparator<VpnProfile>() {
+ public int compare(VpnProfile p1, VpnProfile p2) {
+ return p1.getName().compareTo(p2.getName());
+ }
+
+ public boolean equals(VpnProfile p) {
+ // not used
+ return false;
+ }
+ });
+ for (VpnProfile p : mVpnProfileList) addPreferenceFor(p);
disableProfilePreferencesIfOneActive();
}
@@ -668,6 +791,40 @@ public class VpnSettings extends PreferenceActivity implements
return mVpnManager.createVpnProfile(Enum.valueOf(VpnType.class, type));
}
+ private static final String NAMESPACE_VPN = "vpn";
+ private static final String KEY_PREFIX_IPSEC_PSK = "ipsk000";
+ private static final String KEY_PREFIX_L2TP_SECRET = "lscrt000";
+
+ private void processSecrets(VpnProfile p) {
+ Keystore ks = Keystore.getInstance();
+ switch (p.getType()) {
+ case L2TP_IPSEC_PSK:
+ L2tpIpsecPskProfile pskProfile = (L2tpIpsecPskProfile) p;
+ String keyName = KEY_PREFIX_IPSEC_PSK + p.getId();
+ String presharedKey = pskProfile.getPresharedKey();
+ if (!presharedKey.equals(keyName)) {
+ ks.put(NAMESPACE_VPN, keyName, presharedKey);
+ pskProfile.setPresharedKey(NAMESPACE_VPN + "_" + keyName);
+ }
+ // pass through
+
+ case L2TP:
+ L2tpProfile l2tpProfile = (L2tpProfile) p;
+ keyName = KEY_PREFIX_L2TP_SECRET + p.getId();
+ String secret = l2tpProfile.getSecretString();
+ if (l2tpProfile.isSecretEnabled()) {
+ if (!secret.equals(keyName)) {
+ ks.put(NAMESPACE_VPN, keyName, secret);
+ l2tpProfile.setSecretString(
+ NAMESPACE_VPN + "_" + keyName);
+ }
+ } else {
+ ks.remove(NAMESPACE_VPN, keyName);
+ }
+ break;
+ }
+ }
+
private class VpnPreference extends Preference {
VpnProfile mProfile;
VpnPreference(Context c, VpnProfile p) {