Fix secret EditText display and other fixes.
+ Now it shows shadowed "(unchanged)" (as in wifi settings) and "(not set)" instead of two dots. Patch Set 2: + Show cancellation confirmation dialog only when there's change in profile. Patch Set 3: + Re-enable profile preferences when the reconnect dialog is cancelled.
This commit is contained in:
@@ -1829,7 +1829,7 @@ found in the list of installed applications.</string>
|
||||
<string name="vpn_yes_button">Yes</string>
|
||||
<string name="vpn_no_button">No</string>
|
||||
<string name="vpn_back_button">Back</string>
|
||||
<string name="vpn_mistake_button">No, it's a mistake</string>
|
||||
<string name="vpn_mistake_button">No</string>
|
||||
|
||||
<string name="vpn_menu_done">Save</string>
|
||||
<string name="vpn_menu_cancel">Cancel</string>
|
||||
@@ -1935,6 +1935,10 @@ found in the list of installed applications.</string>
|
||||
<string name="vpn_settings_title">VPN settings</string>
|
||||
<!-- Summary of preference to enter the VPN settings activity -->
|
||||
<string name="vpn_settings_summary">Set up & manage Virtual Private Networks (VPNs)</string>
|
||||
<!-- A secret edit field's grayed out value when it has not been modified -->
|
||||
<string name="vpn_secret_unchanged">(unchanged)</string>
|
||||
<!-- A secret edit field's grayed out value when it has not been set -->
|
||||
<string name="vpn_secret_not_set">(not set)</string>
|
||||
|
||||
<!-- Title of preference group for credential storage settings -->
|
||||
<string name="cstor_settings_category">Credential storage</string>
|
||||
|
@@ -30,9 +30,7 @@ import android.preference.PreferenceGroup;
|
||||
*/
|
||||
class L2tpEditor extends VpnProfileEditor {
|
||||
private CheckBoxPreference mSecret;
|
||||
private EditTextPreference mSecretString;
|
||||
private String mOriginalSecret;
|
||||
private boolean mOriginalSecretEnabled;
|
||||
private SecretHandler mSecretHandler;
|
||||
|
||||
public L2tpEditor(L2tpProfile p) {
|
||||
super(p);
|
||||
@@ -43,11 +41,8 @@ class L2tpEditor extends VpnProfileEditor {
|
||||
Context c = subpanel.getContext();
|
||||
subpanel.addPreference(createSecretPreference(c));
|
||||
subpanel.addPreference(createSecretStringPreference(c));
|
||||
mSecretString.setEnabled(mSecret.isChecked());
|
||||
|
||||
L2tpProfile profile = (L2tpProfile) getProfile();
|
||||
mOriginalSecret = profile.getSecretString();
|
||||
mOriginalSecretEnabled = profile.isSecretEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,9 +50,7 @@ class L2tpEditor extends VpnProfileEditor {
|
||||
String result = super.validate();
|
||||
if (!mSecret.isChecked()) return result;
|
||||
|
||||
return ((result != null)
|
||||
? result
|
||||
: validate(mSecretString, R.string.vpn_a_l2tp_secret));
|
||||
return ((result != null) ? result : mSecretHandler.validate());
|
||||
}
|
||||
|
||||
private Preference createSecretPreference(Context c) {
|
||||
@@ -73,7 +66,7 @@ class L2tpEditor extends VpnProfileEditor {
|
||||
Preference pref, Object newValue) {
|
||||
boolean enabled = (Boolean) newValue;
|
||||
profile.setSecretEnabled(enabled);
|
||||
mSecretString.setEnabled(enabled);
|
||||
mSecretHandler.getPreference().setEnabled(enabled);
|
||||
setSecretTitle(mSecret, R.string.vpn_l2tp_secret,
|
||||
enabled);
|
||||
setSecretSummary(mSecret, enabled);
|
||||
@@ -84,22 +77,22 @@ class L2tpEditor extends VpnProfileEditor {
|
||||
}
|
||||
|
||||
private Preference createSecretStringPreference(Context c) {
|
||||
final L2tpProfile profile = (L2tpProfile) getProfile();
|
||||
mSecretString = createSecretPreference(c,
|
||||
SecretHandler sHandler = mSecretHandler = new SecretHandler(c,
|
||||
R.string.vpn_l2tp_secret_string_title,
|
||||
R.string.vpn_l2tp_secret,
|
||||
profile.getSecretString(),
|
||||
new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(
|
||||
Preference pref, Object newValue) {
|
||||
profile.setSecretString((String) newValue);
|
||||
setSecretSummary(mSecretString,
|
||||
R.string.vpn_l2tp_secret,
|
||||
(String) newValue);
|
||||
return true;
|
||||
R.string.vpn_l2tp_secret) {
|
||||
@Override
|
||||
protected String getSecretFromProfile() {
|
||||
return ((L2tpProfile) getProfile()).getSecretString();
|
||||
}
|
||||
});
|
||||
return mSecretString;
|
||||
|
||||
@Override
|
||||
protected void saveSecretToProfile(String secret) {
|
||||
((L2tpProfile) getProfile()).setSecretString(secret);
|
||||
}
|
||||
};
|
||||
Preference pref = sHandler.getPreference();
|
||||
pref.setEnabled(mSecret.isChecked());
|
||||
return pref;
|
||||
}
|
||||
|
||||
private void setSecretSummary(CheckBoxPreference secret, boolean enabled) {
|
||||
|
@@ -29,6 +29,7 @@ import android.preference.PreferenceGroup;
|
||||
*/
|
||||
class L2tpIpsecPskEditor extends L2tpEditor {
|
||||
private EditTextPreference mPresharedKey;
|
||||
private SecretHandler mPskHandler;
|
||||
|
||||
public L2tpIpsecPskEditor(L2tpIpsecPskProfile p) {
|
||||
super(p);
|
||||
@@ -45,27 +46,23 @@ class L2tpIpsecPskEditor extends L2tpEditor {
|
||||
public String validate() {
|
||||
String result = super.validate();
|
||||
|
||||
return ((result != null)
|
||||
? result
|
||||
: validate(mPresharedKey, R.string.vpn_a_ipsec_presharedkey));
|
||||
return ((result != null) ? result : mPskHandler.validate());
|
||||
}
|
||||
|
||||
private Preference createPresharedKeyPreference(Context c) {
|
||||
final L2tpIpsecPskProfile profile = (L2tpIpsecPskProfile) getProfile();
|
||||
mPresharedKey = createSecretPreference(c,
|
||||
SecretHandler pskHandler = mPskHandler = new SecretHandler(c,
|
||||
R.string.vpn_ipsec_presharedkey_title,
|
||||
R.string.vpn_ipsec_presharedkey,
|
||||
profile.getPresharedKey(),
|
||||
new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(
|
||||
Preference pref, Object newValue) {
|
||||
profile.setPresharedKey((String) newValue);
|
||||
setSecretSummary(mPresharedKey,
|
||||
R.string.vpn_ipsec_presharedkey,
|
||||
(String) newValue);
|
||||
return true;
|
||||
R.string.vpn_ipsec_presharedkey) {
|
||||
@Override
|
||||
protected String getSecretFromProfile() {
|
||||
return ((L2tpIpsecPskProfile) getProfile()).getPresharedKey();
|
||||
}
|
||||
});
|
||||
return mPresharedKey;
|
||||
|
||||
@Override
|
||||
protected void saveSecretToProfile(String secret) {
|
||||
((L2tpIpsecPskProfile) getProfile()).setPresharedKey(secret);
|
||||
}
|
||||
};
|
||||
return pskHandler.getPreference();
|
||||
}
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ import android.net.vpn.L2tpProfile;
|
||||
import android.net.vpn.VpnProfile;
|
||||
import android.net.vpn.VpnType;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceGroup;
|
||||
@@ -47,6 +48,7 @@ public class VpnEditor extends PreferenceActivity {
|
||||
|
||||
private VpnProfileEditor mProfileEditor;
|
||||
private boolean mAddingProfile;
|
||||
private byte[] mOriginalProfileData;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@@ -61,6 +63,10 @@ public class VpnEditor extends PreferenceActivity {
|
||||
addPreferencesFromResource(R.xml.vpn_edit);
|
||||
|
||||
initViewFor(p);
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
p.writeToParcel(parcel, 0);
|
||||
mOriginalProfileData = parcel.marshall();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,7 +96,11 @@ public class VpnEditor extends PreferenceActivity {
|
||||
return true;
|
||||
|
||||
case MENU_CANCEL:
|
||||
if (profileChanged()) {
|
||||
showCancellationConfirmDialog();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
@@ -131,7 +141,7 @@ public class VpnEditor extends PreferenceActivity {
|
||||
return false;
|
||||
}
|
||||
|
||||
setResult(getProfile());
|
||||
if (profileChanged()) setResult(getProfile());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -177,4 +187,17 @@ public class VpnEditor extends PreferenceActivity {
|
||||
private VpnProfile getProfile() {
|
||||
return mProfileEditor.getProfile();
|
||||
}
|
||||
|
||||
private boolean profileChanged() {
|
||||
Parcel newParcel = Parcel.obtain();
|
||||
getProfile().writeToParcel(newParcel, 0);
|
||||
byte[] newData = newParcel.marshall();
|
||||
if (mOriginalProfileData.length == newData.length) {
|
||||
for (int i = 0, n = mOriginalProfileData.length; i < n; i++) {
|
||||
if (mOriginalProfileData[i] != newData[i]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -33,9 +33,6 @@ import android.text.method.PasswordTransformationMethod;
|
||||
* The common class for editing {@link VpnProfile}.
|
||||
*/
|
||||
class VpnProfileEditor {
|
||||
static final String SECRET_SET_INDICATOR =
|
||||
new String(new byte[] {(byte) 1, (byte) 0});
|
||||
|
||||
private static final String KEY_VPN_NAME = "vpn_name";
|
||||
|
||||
private EditTextPreference mName;
|
||||
@@ -147,22 +144,6 @@ class VpnProfileEditor {
|
||||
return pref;
|
||||
}
|
||||
|
||||
protected EditTextPreference createSecretPreference(Context c, int titleId,
|
||||
int fieldNameId, String value,
|
||||
Preference.OnPreferenceChangeListener listener) {
|
||||
EditTextPreference pref = new EditTextPreference(c);
|
||||
pref.setTitle(titleId);
|
||||
pref.setDialogTitle(titleId);
|
||||
pref.getEditText().setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
pref.getEditText().setTransformationMethod(
|
||||
new PasswordTransformationMethod());
|
||||
pref.setText(TextUtils.isEmpty(value) ? "" : SECRET_SET_INDICATOR);
|
||||
setSecretSummary(pref, fieldNameId, value);
|
||||
pref.setPersistent(true);
|
||||
pref.setOnPreferenceChangeListener(listener);
|
||||
return pref;
|
||||
}
|
||||
|
||||
protected String validate(Preference pref, int fieldNameId) {
|
||||
Context c = pref.getContext();
|
||||
String value = (pref instanceof EditTextPreference)
|
||||
@@ -191,15 +172,6 @@ class VpnProfileEditor {
|
||||
: v);
|
||||
}
|
||||
|
||||
protected void setSecretSummary(Preference pref, int fieldNameId,
|
||||
String value) {
|
||||
Context c = pref.getContext();
|
||||
String formatString = TextUtils.isEmpty(value)
|
||||
? c.getString(R.string.vpn_field_not_set)
|
||||
: c.getString(R.string.vpn_field_is_set);
|
||||
pref.setSummary(String.format(formatString, c.getString(fieldNameId)));
|
||||
}
|
||||
|
||||
protected void setSecretTitle(
|
||||
CheckBoxPreference pref, int fieldNameId, boolean enabled) {
|
||||
Context c = pref.getContext();
|
||||
@@ -215,4 +187,69 @@ class VpnProfileEditor {
|
||||
getProfile().setName(newName);
|
||||
setSummary(mName, R.string.vpn_name, newName);
|
||||
}
|
||||
|
||||
// Secret is tricky to handle because empty field may mean "not set" or
|
||||
// "unchanged". This class hides that logic from callers.
|
||||
protected static abstract class SecretHandler {
|
||||
private EditTextPreference mPref;
|
||||
private int mFieldNameId;
|
||||
private boolean mHadSecret;
|
||||
|
||||
protected SecretHandler(Context c, int titleId, int fieldNameId) {
|
||||
String value = getSecretFromProfile();
|
||||
mHadSecret = !TextUtils.isEmpty(value);
|
||||
mFieldNameId = fieldNameId;
|
||||
|
||||
EditTextPreference pref = mPref = new EditTextPreference(c);
|
||||
pref.setTitle(titleId);
|
||||
pref.setDialogTitle(titleId);
|
||||
pref.getEditText().setInputType(
|
||||
InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
pref.getEditText().setTransformationMethod(
|
||||
new PasswordTransformationMethod());
|
||||
pref.setText("");
|
||||
pref.getEditText().setHint(mHadSecret
|
||||
? R.string.vpn_secret_unchanged
|
||||
: R.string.vpn_secret_not_set);
|
||||
setSecretSummary(value);
|
||||
pref.setPersistent(true);
|
||||
saveSecretToProfile("");
|
||||
pref.setOnPreferenceChangeListener(
|
||||
new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(
|
||||
Preference pref, Object newValue) {
|
||||
saveSecretToProfile((String) newValue);
|
||||
setSecretSummary((String) newValue);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected EditTextPreference getPreference() {
|
||||
return mPref;
|
||||
}
|
||||
|
||||
protected String validate() {
|
||||
Context c = mPref.getContext();
|
||||
String value = mPref.getText();
|
||||
return ((TextUtils.isEmpty(value) && !mHadSecret)
|
||||
? String.format(
|
||||
c.getString(R.string.vpn_error_miss_entering),
|
||||
c.getString(mFieldNameId))
|
||||
: null);
|
||||
}
|
||||
|
||||
private void setSecretSummary(String value) {
|
||||
EditTextPreference pref = mPref;
|
||||
Context c = pref.getContext();
|
||||
String formatString = (TextUtils.isEmpty(value) && !mHadSecret)
|
||||
? c.getString(R.string.vpn_field_not_set)
|
||||
: c.getString(R.string.vpn_field_is_set);
|
||||
pref.setSummary(
|
||||
String.format(formatString, c.getString(mFieldNameId)));
|
||||
}
|
||||
|
||||
protected abstract String getSecretFromProfile();
|
||||
protected abstract void saveSecretToProfile(String secret);
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ package com.android.settings.vpn;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SecuritySettings;
|
||||
import static com.android.settings.vpn.VpnProfileEditor.SECRET_SET_INDICATOR;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
@@ -197,7 +196,7 @@ public class VpnSettings extends PreferenceActivity implements
|
||||
return createConnectDialog();
|
||||
|
||||
case DIALOG_RECONNECT:
|
||||
return createReconnectDialogBuilder().create();
|
||||
return createReconnectDialog();
|
||||
|
||||
case DIALOG_AUTH_ERROR:
|
||||
return createAuthErrorDialog();
|
||||
@@ -219,14 +218,44 @@ public class VpnSettings extends PreferenceActivity implements
|
||||
this)
|
||||
.setNegativeButton(getString(android.R.string.cancel),
|
||||
this)
|
||||
.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
removeDialog(DIALOG_CONNECT);
|
||||
onIdle();
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
|
||||
private AlertDialog.Builder createReconnectDialogBuilder() {
|
||||
private Dialog createReconnectDialog() {
|
||||
return createCommonDialogBuilder()
|
||||
.setMessage(R.string.vpn_confirm_reconnect)
|
||||
.create();
|
||||
}
|
||||
|
||||
private Dialog createAuthErrorDialog() {
|
||||
return createCommonDialogBuilder()
|
||||
.setMessage(R.string.vpn_auth_error_dialog_msg)
|
||||
.create();
|
||||
}
|
||||
private Dialog createUnknownServerDialog() {
|
||||
return createCommonDialogBuilder()
|
||||
.setMessage(R.string.vpn_unknown_server_dialog_msg)
|
||||
.setPositiveButton(R.string.vpn_yes_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int w) {
|
||||
VpnProfile p = mConnectingActor.getProfile();
|
||||
onIdle();
|
||||
startVpnEditor(p);
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
|
||||
private AlertDialog.Builder createCommonDialogBuilder() {
|
||||
return new AlertDialog.Builder(this)
|
||||
.setTitle(android.R.string.dialog_alert_title)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setMessage(R.string.vpn_confirm_reconnect)
|
||||
.setPositiveButton(R.string.vpn_yes_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int w) {
|
||||
@@ -246,26 +275,6 @@ public class VpnSettings extends PreferenceActivity implements
|
||||
});
|
||||
}
|
||||
|
||||
private Dialog createAuthErrorDialog() {
|
||||
return createReconnectDialogBuilder()
|
||||
.setMessage(R.string.vpn_auth_error_dialog_msg)
|
||||
.create();
|
||||
}
|
||||
|
||||
private Dialog createUnknownServerDialog() {
|
||||
return createReconnectDialogBuilder()
|
||||
.setMessage(R.string.vpn_unknown_server_dialog_msg)
|
||||
.setPositiveButton(R.string.vpn_yes_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int w) {
|
||||
VpnProfile p = mConnectingActor.getProfile();
|
||||
onIdle();
|
||||
startVpnEditor(p);
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
@@ -413,6 +422,7 @@ public class VpnSettings extends PreferenceActivity implements
|
||||
}
|
||||
} else {
|
||||
removeDialog(DIALOG_CONNECT);
|
||||
onIdle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -707,6 +717,7 @@ public class VpnSettings extends PreferenceActivity implements
|
||||
}
|
||||
|
||||
private void onIdle() {
|
||||
Log.d(TAG, " onIdle()");
|
||||
mActiveProfile = null;
|
||||
mConnectingActor = null;
|
||||
enableProfilePreferences();
|
||||
@@ -853,28 +864,28 @@ public class VpnSettings extends PreferenceActivity implements
|
||||
case L2TP_IPSEC_PSK:
|
||||
L2tpIpsecPskProfile pskProfile = (L2tpIpsecPskProfile) p;
|
||||
String presharedKey = pskProfile.getPresharedKey();
|
||||
if (!presharedKey.equals(SECRET_SET_INDICATOR)) {
|
||||
String keyName = KEY_PREFIX_IPSEC_PSK + p.getId();
|
||||
if (!TextUtils.isEmpty(presharedKey)) {
|
||||
int ret = ks.put(NAMESPACE_VPN, keyName, presharedKey);
|
||||
if (ret < 0) {
|
||||
if (ret != 0) {
|
||||
Log.e(TAG, "keystore write failed: key=" + keyName);
|
||||
}
|
||||
pskProfile.setPresharedKey(keyNameForDaemon(keyName));
|
||||
}
|
||||
pskProfile.setPresharedKey(keyNameForDaemon(keyName));
|
||||
// pass through
|
||||
|
||||
case L2TP:
|
||||
L2tpProfile l2tpProfile = (L2tpProfile) p;
|
||||
String keyName = KEY_PREFIX_L2TP_SECRET + p.getId();
|
||||
keyName = KEY_PREFIX_L2TP_SECRET + p.getId();
|
||||
if (l2tpProfile.isSecretEnabled()) {
|
||||
String secret = l2tpProfile.getSecretString();
|
||||
if (!secret.equals(SECRET_SET_INDICATOR)) {
|
||||
if (!TextUtils.isEmpty(secret)) {
|
||||
int ret = ks.put(NAMESPACE_VPN, keyName, secret);
|
||||
if (ret < 0) {
|
||||
if (ret != 0) {
|
||||
Log.e(TAG, "keystore write failed: key=" + keyName);
|
||||
}
|
||||
l2tpProfile.setSecretString(keyNameForDaemon(keyName));
|
||||
}
|
||||
l2tpProfile.setSecretString(keyNameForDaemon(keyName));
|
||||
} else {
|
||||
ks.remove(NAMESPACE_VPN, keyName);
|
||||
}
|
||||
|
Reference in New Issue
Block a user