diff --git a/res/layout/vpn_dialog.xml b/res/layout/vpn_dialog.xml
index d7e7f95ad97..620b43fcfab 100644
--- a/res/layout/vpn_dialog.xml
+++ b/res/layout/vpn_dialog.xml
@@ -132,6 +132,9 @@
+
diff --git a/res/menu/vpn.xml b/res/menu/vpn.xml
index 22646d130f1..7b35c702f43 100644
--- a/res/menu/vpn.xml
+++ b/res/menu/vpn.xml
@@ -20,8 +20,4 @@
android:title="@string/vpn_create"
android:icon="@drawable/ic_menu_add_white"
android:showAsAction="always" />
-
diff --git a/src/com/android/settings/vpn2/ConfigDialog.java b/src/com/android/settings/vpn2/ConfigDialog.java
index 6b035fda86a..a13e29dbad5 100644
--- a/src/com/android/settings/vpn2/ConfigDialog.java
+++ b/src/com/android/settings/vpn2/ConfigDialog.java
@@ -20,6 +20,7 @@ import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
+import android.os.SystemProperties;
import android.security.Credentials;
import android.security.KeyStore;
import android.text.Editable;
@@ -29,6 +30,7 @@ import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
+import android.widget.CompoundButton;
import android.widget.Spinner;
import android.widget.TextView;
@@ -45,7 +47,8 @@ import java.net.InetAddress;
* {@see AppDialog}
*/
class ConfigDialog extends AlertDialog implements TextWatcher,
- View.OnClickListener, AdapterView.OnItemSelectedListener {
+ View.OnClickListener, AdapterView.OnItemSelectedListener,
+ CompoundButton.OnCheckedChangeListener {
private final KeyStore mKeyStore = KeyStore.getInstance();
private final DialogInterface.OnClickListener mListener;
private final VpnProfile mProfile;
@@ -72,6 +75,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
private Spinner mIpsecServerCert;
private CheckBox mSaveLogin;
private CheckBox mShowOptions;
+ private CheckBox mAlwaysOnVpn;
ConfigDialog(Context context, DialogInterface.OnClickListener listener,
VpnProfile profile, boolean editing, boolean exists) {
@@ -108,6 +112,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
mIpsecServerCert = (Spinner) mView.findViewById(R.id.ipsec_server_cert);
mSaveLogin = (CheckBox) mView.findViewById(R.id.save_login);
mShowOptions = (CheckBox) mView.findViewById(R.id.show_options);
+ mAlwaysOnVpn = (CheckBox) mView.findViewById(R.id.always_on_vpn);
// Second, copy values from the profile.
mName.setText(mProfile.name);
@@ -124,13 +129,21 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
mL2tpSecret.setText(mProfile.l2tpSecret);
mIpsecIdentifier.setText(mProfile.ipsecIdentifier);
mIpsecSecret.setText(mProfile.ipsecSecret);
- loadCertificates(mIpsecUserCert, Credentials.USER_PRIVATE_KEY,
- 0, mProfile.ipsecUserCert);
+ loadCertificates(mIpsecUserCert, Credentials.USER_PRIVATE_KEY, 0, mProfile.ipsecUserCert);
loadCertificates(mIpsecCaCert, Credentials.CA_CERTIFICATE,
R.string.vpn_no_ca_cert, mProfile.ipsecCaCert);
loadCertificates(mIpsecServerCert, Credentials.USER_CERTIFICATE,
R.string.vpn_no_server_cert, mProfile.ipsecServerCert);
mSaveLogin.setChecked(mProfile.saveLogin);
+ mAlwaysOnVpn.setChecked(mProfile.key.equals(VpnUtils.getLockdownVpn()));
+ mAlwaysOnVpn.setOnCheckedChangeListener(this);
+ // Update SaveLogin checkbox after Always-on checkbox is updated
+ updateSaveLoginStatus();
+
+ // Hide lockdown VPN on devices that require IMS authentication
+ if (SystemProperties.getBoolean("persist.radio.imsregrequired", false)) {
+ mAlwaysOnVpn.setVisibility(View.GONE);
+ }
// Third, add listeners to required fields.
mName.addTextChangedListener(this);
@@ -242,6 +255,27 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
public void onNothingSelected(AdapterView> parent) {
}
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
+ if (compoundButton == mAlwaysOnVpn) {
+ updateSaveLoginStatus();
+ }
+ }
+
+ public boolean isVpnAlwaysOn() {
+ return mAlwaysOnVpn.isChecked();
+ }
+
+ private void updateSaveLoginStatus() {
+ if (mAlwaysOnVpn.isChecked()) {
+ mSaveLogin.setChecked(true);
+ mSaveLogin.setEnabled(false);
+ } else {
+ mSaveLogin.setChecked(mProfile.saveLogin);
+ mSaveLogin.setEnabled(true);
+ }
+ }
+
private void showAdvancedOptions() {
mView.findViewById(R.id.options).setVisibility(View.VISIBLE);
mShowOptions.setVisibility(View.GONE);
diff --git a/src/com/android/settings/vpn2/ConfigDialogFragment.java b/src/com/android/settings/vpn2/ConfigDialogFragment.java
index d145ba30e4c..fc49fd86cf4 100644
--- a/src/com/android/settings/vpn2/ConfigDialogFragment.java
+++ b/src/com/android/settings/vpn2/ConfigDialogFragment.java
@@ -22,6 +22,7 @@ import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
+import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.os.Bundle;
import android.os.RemoteException;
@@ -112,8 +113,10 @@ public class ConfigDialogFragment extends DialogFragment implements
// Flush out old version of profile
disconnect(profile);
+ updateLockdownVpn(dialog.isVpnAlwaysOn(), profile);
+
// If we are not editing, connect!
- if (!dialog.isEditing()) {
+ if (!dialog.isEditing() && !VpnUtils.isVpnLockdown(profile.key)) {
try {
connect(profile);
} catch (RemoteException e) {
@@ -128,15 +131,7 @@ public class ConfigDialogFragment extends DialogFragment implements
KeyStore keyStore = KeyStore.getInstance();
keyStore.delete(Credentials.VPN + profile.key, KeyStore.UID_SELF);
- // If this was the current lockdown VPN, clear it.
- if (Arrays.equals(profile.key.getBytes(), keyStore.get(Credentials.LOCKDOWN_VPN))) {
- keyStore.delete(Credentials.LOCKDOWN_VPN);
- try {
- mService.updateLockdownVpn();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to clear lockdown VPN configuration");
- }
- }
+ updateLockdownVpn(false, profile);
}
dismiss();
}
@@ -147,6 +142,30 @@ public class ConfigDialogFragment extends DialogFragment implements
super.onCancel(dialog);
}
+ private void updateLockdownVpn(boolean isVpnAlwaysOn, VpnProfile profile) {
+ // Save lockdown vpn
+ if (isVpnAlwaysOn) {
+ // Show toast if vpn profile is not valid
+ if (!profile.isValidLockdownProfile()) {
+ Toast.makeText(getContext(), R.string.vpn_lockdown_config_error,
+ Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ // Update only if lockdown vpn has been changed
+ if (!VpnUtils.isVpnLockdown(profile.key)) {
+ final ConnectivityManager conn = ConnectivityManager.from(getActivity());
+ conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null);
+ VpnUtils.setLockdownVpn(getContext(), profile.key);
+ }
+ } else {
+ // update only if lockdown vpn has been changed
+ if (VpnUtils.isVpnLockdown(profile.key)) {
+ VpnUtils.clearLockdownVpn(getContext());
+ }
+ }
+ }
+
private void connect(VpnProfile profile) throws RemoteException {
try {
mService.startLegacyVpn(profile);
diff --git a/src/com/android/settings/vpn2/LockdownConfigFragment.java b/src/com/android/settings/vpn2/LockdownConfigFragment.java
deleted file mode 100644
index 8f19fa6c2bb..00000000000
--- a/src/com/android/settings/vpn2/LockdownConfigFragment.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2015 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 android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.security.Credentials;
-import android.security.KeyStore;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.Toast;
-
-import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnProfile;
-import com.android.settings.R;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Dialog to configure always-on VPN.
- */
-public class LockdownConfigFragment extends DialogFragment {
- private List mProfiles;
- private List mApps;
- private List mTitles;
- private int mCurrentIndex;
-
- private static final String TAG_LOCKDOWN = "lockdown";
- private static final String LOG_TAG = "LockdownConfigFragment";
-
- private static class TitleAdapter extends ArrayAdapter {
- public TitleAdapter(Context context, List objects) {
- super(context, com.android.internal.R.layout.select_dialog_singlechoice_material,
- android.R.id.text1, objects);
- }
- }
-
- public static void show(VpnSettings parent) {
- if (!parent.isAdded()) return;
-
- final LockdownConfigFragment dialog = new LockdownConfigFragment();
- dialog.show(parent.getFragmentManager(), TAG_LOCKDOWN);
- }
-
- private void initProfiles(KeyStore keyStore, Resources res) {
- final ConnectivityManager cm = ConnectivityManager.from(getActivity());
- final String lockdownKey = VpnUtils.getLockdownVpn();
- final String alwaysOnPackage = cm.getAlwaysOnVpnPackageForUser(UserHandle.myUserId());
-
- // Legacy VPN has a separate always-on mechanism which takes over the whole device, so
- // this option is restricted to the primary user only.
- if (UserManager.get(getContext()).isPrimaryUser()) {
- mProfiles = VpnSettings.loadVpnProfiles(keyStore, VpnProfile.TYPE_PPTP);
- } else {
- mProfiles = Collections.emptyList();
- }
- mApps = VpnSettings.getVpnApps(getActivity(), /* includeProfiles */ false);
-
- mTitles = new ArrayList<>(1 + mProfiles.size() + mApps.size());
- mTitles.add(res.getText(R.string.vpn_lockdown_none));
- mCurrentIndex = 0;
-
- // Add true lockdown VPNs to the list first.
- for (VpnProfile profile : mProfiles) {
- if (TextUtils.equals(profile.key, lockdownKey)) {
- mCurrentIndex = mTitles.size();
- }
- mTitles.add(profile.name);
- }
-
- // Add third-party app VPNs (VpnService) for the current profile to set as always-on.
- for (AppVpnInfo app : mApps) {
- try {
- String appName = VpnConfig.getVpnLabel(getContext(), app.packageName).toString();
- if (TextUtils.equals(app.packageName, alwaysOnPackage)) {
- mCurrentIndex = mTitles.size();
- }
- mTitles.add(appName);
- } catch (PackageManager.NameNotFoundException pkgNotFound) {
- Log.w(LOG_TAG, "VPN package not found: '" + app.packageName + "'", pkgNotFound);
- }
- }
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Context context = getActivity();
- final KeyStore keyStore = KeyStore.getInstance();
-
- initProfiles(keyStore, context.getResources());
-
- final AlertDialog.Builder builder = new AlertDialog.Builder(context);
- final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
-
- builder.setTitle(R.string.vpn_menu_lockdown);
-
- final View view = dialogInflater.inflate(R.layout.vpn_lockdown_editor, null, false);
- final ListView listView = (ListView) view.findViewById(android.R.id.list);
- listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- listView.setAdapter(new TitleAdapter(context, mTitles));
- listView.setItemChecked(mCurrentIndex, true);
- builder.setView(view);
-
- builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- final int newIndex = listView.getCheckedItemPosition();
- if (mCurrentIndex == newIndex) return;
-
- final ConnectivityManager conn = ConnectivityManager.from(getActivity());
-
- if (newIndex == 0) {
- keyStore.delete(Credentials.LOCKDOWN_VPN);
- conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null);
- } else if (newIndex <= mProfiles.size()) {
- final VpnProfile profile = mProfiles.get(newIndex - 1);
- if (!profile.isValidLockdownProfile()) {
- Toast.makeText(context, R.string.vpn_lockdown_config_error,
- Toast.LENGTH_LONG).show();
- return;
- }
- conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null);
- keyStore.put(Credentials.LOCKDOWN_VPN, profile.key.getBytes(),
- KeyStore.UID_SELF, /* flags */ 0);
- } else {
- keyStore.delete(Credentials.LOCKDOWN_VPN);
-
- final AppVpnInfo appVpn = mApps.get(newIndex - 1 - mProfiles.size());
- conn.setAlwaysOnVpnPackageForUser(appVpn.userId, appVpn.packageName);
- }
-
- // kick profiles since we changed them
- conn.updateLockdownVpn();
- }
- });
-
- return builder.create();
- }
-}
-
diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java
index 64403dd9a6e..f6058960c0c 100644
--- a/src/com/android/settings/vpn2/VpnSettings.java
+++ b/src/com/android/settings/vpn2/VpnSettings.java
@@ -80,7 +80,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements
private static final int RESCAN_MESSAGE = 0;
private static final int RESCAN_INTERVAL_MS = 1000;
- private static final String EXTRA_PICK_LOCKDOWN = "android.net.vpn.PICK_LOCKDOWN";
private static final NetworkRequest VPN_REQUEST = new NetworkRequest.Builder()
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
@@ -143,11 +142,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements
menu.getItem(i).setEnabled(!mUnavailable);
}
}
-
- // Hide lockdown VPN on devices that require IMS authentication
- if (SystemProperties.getBoolean("persist.radio.imsregrequired", false)) {
- menu.findItem(R.id.vpn_lockdown).setVisible(false);
- }
}
@Override
@@ -163,10 +157,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements
ConfigDialogFragment.show(this, profile, true /* editing */, false /* exists */);
return true;
}
- case R.id.vpn_lockdown: {
- LockdownConfigFragment.show(this);
- return true;
- }
}
return super.onOptionsItemSelected(item);
}
@@ -186,12 +176,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements
getEmptyTextView().setText(R.string.vpn_no_vpns_added);
}
- final boolean pickLockdown = getActivity()
- .getIntent().getBooleanExtra(EXTRA_PICK_LOCKDOWN, false);
- if (pickLockdown) {
- LockdownConfigFragment.show(this);
- }
-
// Start monitoring
mConnectivityManager.registerNetworkCallback(VPN_REQUEST, mNetworkCallback);
diff --git a/src/com/android/settings/vpn2/VpnUtils.java b/src/com/android/settings/vpn2/VpnUtils.java
index 122816ad487..6afa79b73bd 100644
--- a/src/com/android/settings/vpn2/VpnUtils.java
+++ b/src/com/android/settings/vpn2/VpnUtils.java
@@ -21,7 +21,9 @@ import android.security.Credentials;
import android.security.KeyStore;
/**
- * Utility functions for vpn
+ * Utility functions for vpn.
+ *
+ * Keystore methods should only be called in system user
*/
public class VpnUtils {
@@ -35,4 +37,15 @@ public class VpnUtils {
// Always notify ConnectivityManager after keystore update
context.getSystemService(ConnectivityManager.class).updateLockdownVpn();
}
+
+ public static void setLockdownVpn(Context context, String lockdownKey) {
+ KeyStore.getInstance().put(Credentials.LOCKDOWN_VPN, lockdownKey.getBytes(),
+ KeyStore.UID_SELF, /* flags */ 0);
+ // Always notify ConnectivityManager after keystore update
+ context.getSystemService(ConnectivityManager.class).updateLockdownVpn();
+ }
+
+ public static boolean isVpnLockdown(String key) {
+ return key.equals(getLockdownVpn());
+ }
}