From 6005aefd44ca073b4c53ceb912b72c0215072799 Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Thu, 17 Mar 2016 20:58:50 +0000 Subject: [PATCH] Remove VPN Overflow menu - Move always-on option for legacy vpn into the legacy vpn config page - This implementation doesn't show dialogue when replacing existing always-on vpn - Continue to disable lockdown option for legacy vpn when "persist.radio.imsregrequired" is true. Not applying to vpn app - Force to save account info when legacy vpn is always-on - When legacy vpn is always-on, don't try to connect. (Otherwise, an exception is thrown) TODO: Remove EXTRA_PICK_LOCKDOWN in LockdownVpnTracker in framework Bug: 26950700 Change-Id: Ia80669359c0b7cdb955c84937156c020ac6e9af5 --- res/layout/vpn_dialog.xml | 3 + res/menu/vpn.xml | 4 - .../android/settings/vpn2/ConfigDialog.java | 40 ++++- .../settings/vpn2/ConfigDialogFragment.java | 39 ++-- .../settings/vpn2/LockdownConfigFragment.java | 169 ------------------ .../android/settings/vpn2/VpnSettings.java | 16 -- src/com/android/settings/vpn2/VpnUtils.java | 15 +- 7 files changed, 83 insertions(+), 203 deletions(-) delete mode 100644 src/com/android/settings/vpn2/LockdownConfigFragment.java 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()); + } }