diff options
author | Hung-ying Tyan <tyanh@google.com> | 2009-07-06 17:26:34 +0800 |
---|---|---|
committer | Hung-ying Tyan <tyanh@google.com> | 2009-07-06 18:47:47 +0800 |
commit | 0a59b500147cc038541f6f2897de7e28c15a12c1 (patch) | |
tree | f5d44650a99de7e5bc86933e8764d3d51c970da3 /src/com | |
parent | eb7836f11ec4e9753db7c6ecd9414e153bb7bdbe (diff) | |
download | packages_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.java | 33 | ||||
-rw-r--r-- | src/com/android/settings/vpn/L2tpEditor.java | 6 | ||||
-rw-r--r-- | src/com/android/settings/vpn/L2tpIpsecEditor.java | 6 | ||||
-rw-r--r-- | src/com/android/settings/vpn/L2tpIpsecPskEditor.java | 7 | ||||
-rw-r--r-- | src/com/android/settings/vpn/Util.java | 6 | ||||
-rw-r--r-- | src/com/android/settings/vpn/VpnEditor.java | 7 | ||||
-rw-r--r-- | src/com/android/settings/vpn/VpnProfileEditor.java | 7 | ||||
-rw-r--r-- | src/com/android/settings/vpn/VpnSettings.java | 189 |
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) { |