From 14c2ac4dcb17c27e065384e69c9f2e24dcbf22aa Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Tue, 15 Mar 2016 18:48:08 +0000 Subject: [PATCH] Per vpn setting change in VPN list - Show admin support details when user taps on a cell and user restriction is on - Show always-on-vpn active status in preference summary - User can still open non-configurable per-VPN info page even when user restriction is applied - Rename ConfigPreference to LegacyVpnPreference - Move summary String handling into ManageablePreference - ManageablePreference inherits GearPreference to reuse the code - Don't show disconnect dialog when always-on is enabled BUG=26950700 Change-Id: I37b087879cf3b674df528e7787d7bb1eead3310f --- res/layout/preference_vpn.xml | 39 ----------- res/values/strings.xml | 4 ++ .../android/settings/vpn2/AppPreference.java | 29 +++----- ...eference.java => LegacyVpnPreference.java} | 38 +++++----- .../settings/vpn2/ManageablePreference.java | 64 ++++++++++++----- .../android/settings/vpn2/VpnSettings.java | 69 ++++++++++--------- 6 files changed, 118 insertions(+), 125 deletions(-) delete mode 100644 res/layout/preference_vpn.xml rename src/com/android/settings/vpn2/{ConfigPreference.java => LegacyVpnPreference.java} (76%) diff --git a/res/layout/preference_vpn.xml b/res/layout/preference_vpn.xml deleted file mode 100644 index 95d3253edae..00000000000 --- a/res/layout/preference_vpn.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - diff --git a/res/values/strings.xml b/res/values/strings.xml index f06383fe053..ec53f221a15 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3396,6 +3396,8 @@ because it runs in the same process as %2$s: %1$s and %2$s + + %1$s, %2$s %1$s and %2$s @@ -5207,6 +5209,8 @@ Always-on VPN No VPNs added. + + Always-on active Select a VPN profile to always remain connected to. Network traffic will only be allowed when connected to this VPN. diff --git a/src/com/android/settings/vpn2/AppPreference.java b/src/com/android/settings/vpn2/AppPreference.java index af4192eff4a..e3649a897b0 100644 --- a/src/com/android/settings/vpn2/AppPreference.java +++ b/src/com/android/settings/vpn2/AppPreference.java @@ -22,11 +22,9 @@ import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.support.v7.preference.Preference; -import android.view.View.OnClickListener; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; -import com.android.settings.R; /** * {@link android.support.v7.preference.Preference} containing information about a VPN @@ -39,10 +37,15 @@ public class AppPreference extends ManageablePreference { private int mState = STATE_DISCONNECTED; private String mPackageName; private String mName; - private int mUserId = UserHandle.USER_NULL; - public AppPreference(Context context, OnClickListener onManage) { - super(context, null /* attrs */, onManage); + public AppPreference(Context context) { + super(context, null /* attrs */); + } + + @Override + public void setUserId(int userId) { + super.setUserId(userId); + update(); } public PackageInfo getPackageInfo() { @@ -67,15 +70,6 @@ public class AppPreference extends ManageablePreference { update(); } - public int getUserId() { - return mUserId; - } - - public void setUserId(int userId) { - mUserId = userId; - update(); - } - public int getState() { return mState; } @@ -90,8 +84,7 @@ public class AppPreference extends ManageablePreference { return; } - final String[] states = getContext().getResources().getStringArray(R.array.vpn_states); - setSummary(mState != STATE_DISCONNECTED ? states[mState] : ""); + setSummary(getSummaryString(mState == STATE_DISCONNECTED ? STATE_NONE : mState)); mName = mPackageName; Drawable icon = null; @@ -140,9 +133,9 @@ public class AppPreference extends ManageablePreference { result = mUserId - another.mUserId; } return result; - } else if (preference instanceof ConfigPreference) { + } else if (preference instanceof LegacyVpnPreference) { // Use comparator from ConfigPreference - ConfigPreference another = (ConfigPreference) preference; + LegacyVpnPreference another = (LegacyVpnPreference) preference; return -another.compareTo(this); } else { return super.compareTo(preference); diff --git a/src/com/android/settings/vpn2/ConfigPreference.java b/src/com/android/settings/vpn2/LegacyVpnPreference.java similarity index 76% rename from src/com/android/settings/vpn2/ConfigPreference.java rename to src/com/android/settings/vpn2/LegacyVpnPreference.java index c7ecddb4e28..a9b8aece9a7 100644 --- a/src/com/android/settings/vpn2/ConfigPreference.java +++ b/src/com/android/settings/vpn2/LegacyVpnPreference.java @@ -18,28 +18,24 @@ package com.android.settings.vpn2; import android.content.Context; import android.support.v7.preference.Preference; -import android.view.View.OnClickListener; +import android.view.View; import com.android.internal.net.VpnProfile; import com.android.settings.R; - import static com.android.internal.net.LegacyVpnInfo.STATE_CONNECTED; /** - * {@link android.support.v7.preference.Preference} referencing a VPN - * configuration. Tracks the underlying profile and its connection - * state. + * {@link android.support.v7.preference.Preference} tracks the underlying legacy vpn profile and + * its connection state. */ -public class ConfigPreference extends ManageablePreference { - public static int STATE_NONE = -1; - +public class LegacyVpnPreference extends ManageablePreference { private VpnProfile mProfile; /** One of the STATE_* fields from LegacyVpnInfo, or STATE_NONE */ private int mState = STATE_NONE; - ConfigPreference(Context context, OnClickListener onManage) { - super(context, null /* attrs */, onManage); + LegacyVpnPreference(Context context) { + super(context, null /* attrs */); } public VpnProfile getProfile() { @@ -57,12 +53,7 @@ public class ConfigPreference extends ManageablePreference { } private void update() { - if (mState == STATE_NONE) { - setSummary(""); - } else { - final String[] states = getContext().getResources().getStringArray(R.array.vpn_states); - setSummary(states[mState]); - } + setSummary(getSummaryString(mState)); if (mProfile != null) { setIcon(R.mipmap.ic_launcher_settings); setTitle(mProfile.name); @@ -72,8 +63,8 @@ public class ConfigPreference extends ManageablePreference { @Override public int compareTo(Preference preference) { - if (preference instanceof ConfigPreference) { - ConfigPreference another = (ConfigPreference) preference; + if (preference instanceof LegacyVpnPreference) { + LegacyVpnPreference another = (LegacyVpnPreference) preference; int result; if ((result = another.mState - mState) == 0 && (result = mProfile.name.compareToIgnoreCase(another.mProfile.name)) == 0 && @@ -93,5 +84,14 @@ public class ConfigPreference extends ManageablePreference { return super.compareTo(preference); } } -} + @Override + public void onClick(View v) { + if (v.getId() == R.id.settings_button && isDisabledByAdmin()) { + performClick(); + return; + } + super.onClick(v); + } + +} \ No newline at end of file diff --git a/src/com/android/settings/vpn2/ManageablePreference.java b/src/com/android/settings/vpn2/ManageablePreference.java index ec8a37b2855..ad8a8a31168 100644 --- a/src/com/android/settings/vpn2/ManageablePreference.java +++ b/src/com/android/settings/vpn2/ManageablePreference.java @@ -17,35 +17,63 @@ package com.android.settings.vpn2; import android.content.Context; -import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceViewHolder; +import android.content.res.Resources; +import android.os.UserHandle; +import android.os.UserManager; +import android.text.TextUtils; import android.util.AttributeSet; -import android.view.View; -import android.view.View.OnClickListener; +import com.android.settings.GearPreference; import com.android.settings.R; /** - * Preference with an additional gear icon. Touching the gear icon triggers an - * onChange event. + * This class sets appropriate enabled state and user admin message when userId is set */ -public class ManageablePreference extends Preference { - OnClickListener mListener; - View mManageView; +public abstract class ManageablePreference extends GearPreference { - public ManageablePreference(Context context, AttributeSet attrs, OnClickListener onManage) { + public static int STATE_NONE = -1; + + boolean mIsAlwaysOn = false; + int mUserId; + + public ManageablePreference(Context context, AttributeSet attrs) { super(context, attrs); - mListener = onManage; setPersistent(false); setOrder(0); - setWidgetLayoutResource(R.layout.preference_vpn); + setUserId(UserHandle.myUserId()); } - @Override - public void onBindViewHolder(PreferenceViewHolder view) { - mManageView = view.findViewById(R.id.manage); - mManageView.setOnClickListener(mListener); - mManageView.setTag(this); - super.onBindViewHolder(view); + public int getUserId() { + return mUserId; + } + + public void setUserId(int userId) { + mUserId = userId; + checkRestrictionAndSetDisabled(UserManager.DISALLOW_CONFIG_VPN, userId); + } + + public boolean isAlwaysOn() { + return mIsAlwaysOn; + } + + public void setAlwaysOn(boolean isEnabled) { + mIsAlwaysOn = isEnabled; + } + + /** + * State is not shown for {@code STATE_NONE} + * + * @return summary string showing current connection state and always-on-vpn state + */ + protected String getSummaryString(int state) { + final Resources res = getContext().getResources(); + final String[] states = res.getStringArray(R.array.vpn_states); + String summary = state == STATE_NONE ? "" : states[state]; + if (mIsAlwaysOn) { + final String alwaysOnString = res.getString(R.string.vpn_always_on_active); + summary = TextUtils.isEmpty(summary) ? alwaysOnString : res.getString( + R.string.join_two_unrelated_items, summary, alwaysOnString); + } + return summary; } } diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java index c4576151c14..64403dd9a6e 100644 --- a/src/com/android/settings/vpn2/VpnSettings.java +++ b/src/com/android/settings/vpn2/VpnSettings.java @@ -48,13 +48,14 @@ import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; -import android.view.View; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; import com.android.internal.util.ArrayUtils; +import com.android.settings.GearPreference; +import com.android.settings.GearPreference.OnGearClickListener; import com.android.settings.R; import com.android.settings.RestrictedSettingsFragment; import com.android.settingslib.RestrictedLockUtils; @@ -93,7 +94,7 @@ public class VpnSettings extends RestrictedSettingsFragment implements private final KeyStore mKeyStore = KeyStore.getInstance(); - private Map mConfigPreferences = new ArrayMap<>(); + private Map mLegacyVpnPreferences = new ArrayMap<>(); private Map mAppPreferences = new ArrayMap<>(); private Handler mUpdater; @@ -155,7 +156,7 @@ public class VpnSettings extends RestrictedSettingsFragment implements case R.id.vpn_create: { // Generate a new key. Here we just use the current time. long millis = System.currentTimeMillis(); - while (mConfigPreferences.containsKey(Long.toHexString(millis))) { + while (mLegacyVpnPreferences.containsKey(Long.toHexString(millis))) { ++millis; } VpnProfile profile = new VpnProfile(Long.toHexString(millis)); @@ -229,7 +230,8 @@ public class VpnSettings extends RestrictedSettingsFragment implements final List connectedLegacyVpns = getConnectedLegacyVpns(); final List connectedAppVpns = getConnectedAppVpns(); - final Set readOnlyUsers = getReadOnlyUserProfiles(); + final Set alwaysOnAppVpnInfos = getAlwaysOnAppVpnInfos(); + final String lockdownVpnKey = VpnUtils.getLockdownVpn(); // Refresh list of VPNs getActivity().runOnUiThread(new Runnable() { @@ -244,20 +246,20 @@ public class VpnSettings extends RestrictedSettingsFragment implements final Set updates = new ArraySet<>(); for (VpnProfile profile : vpnProfiles) { - ConfigPreference p = findOrCreatePreference(profile); - p.setState(ConfigPreference.STATE_NONE); - p.setEnabled(!readOnlyUsers.contains(UserHandle.myUserId())); + LegacyVpnPreference p = findOrCreatePreference(profile); + p.setState(LegacyVpnPreference.STATE_NONE); + p.setAlwaysOn(lockdownVpnKey != null && lockdownVpnKey.equals(profile.key)); updates.add(p); } for (AppVpnInfo app : vpnApps) { AppPreference p = findOrCreatePreference(app); p.setState(AppPreference.STATE_DISCONNECTED); - p.setEnabled(!readOnlyUsers.contains(app.userId)); + p.setAlwaysOn(alwaysOnAppVpnInfos.contains(app)); updates.add(p); } // Trim preferences for deleted VPNs - mConfigPreferences.values().retainAll(updates); + mLegacyVpnPreferences.values().retainAll(updates); mAppPreferences.values().retainAll(updates); final PreferenceGroup vpnGroup = getPreferenceScreen(); @@ -277,7 +279,7 @@ public class VpnSettings extends RestrictedSettingsFragment implements // Mark connected VPNs for (LegacyVpnInfo info : connectedLegacyVpns) { - final ConfigPreference preference = mConfigPreferences.get(info.key); + final LegacyVpnPreference preference = mLegacyVpnPreferences.get(info.key); if (preference != null) { preference.setState(info.state); } @@ -297,8 +299,9 @@ public class VpnSettings extends RestrictedSettingsFragment implements @Override public boolean onPreferenceClick(Preference preference) { - if (preference instanceof ConfigPreference) { - VpnProfile profile = ((ConfigPreference) preference).getProfile(); + if (preference instanceof LegacyVpnPreference) { + LegacyVpnPreference pref = (LegacyVpnPreference) preference; + VpnProfile profile = pref.getProfile(); if (mConnectedLegacyVpn != null && profile.key.equals(mConnectedLegacyVpn.key) && mConnectedLegacyVpn.state == LegacyVpnInfo.STATE_CONNECTED) { try { @@ -312,6 +315,11 @@ public class VpnSettings extends RestrictedSettingsFragment implements return true; } else if (preference instanceof AppPreference) { AppPreference pref = (AppPreference) preference; + if (pref.isAlwaysOn()) { + // User can't disconnect vpn when always-on is enabled + return true; + } + boolean connected = (pref.getState() == AppPreference.STATE_CONNECTED); if (!connected) { @@ -343,18 +351,15 @@ public class VpnSettings extends RestrictedSettingsFragment implements return R.string.help_url_vpn; } - private View.OnClickListener mManageListener = new View.OnClickListener() { + private OnGearClickListener mGearListener = new OnGearClickListener() { @Override - public void onClick(View view) { - Object tag = view.getTag(); - - if (tag instanceof ConfigPreference) { - ConfigPreference pref = (ConfigPreference) tag; + public void onGearClick(GearPreference p) { + if (p instanceof LegacyVpnPreference) { + LegacyVpnPreference pref = (LegacyVpnPreference) p; ConfigDialogFragment.show(VpnSettings.this, pref.getProfile(), true /* editing */, true /* exists */); - } else if (tag instanceof AppPreference) { - AppPreference pref = (AppPreference) tag; - boolean connected = (pref.getState() == AppPreference.STATE_CONNECTED); + } else if (p instanceof AppPreference) { + AppPreference pref = (AppPreference) p;; AppManagementFragment.show(getPrefContext(), pref); } } @@ -377,12 +382,13 @@ public class VpnSettings extends RestrictedSettingsFragment implements }; @UiThread - private ConfigPreference findOrCreatePreference(VpnProfile profile) { - ConfigPreference pref = mConfigPreferences.get(profile.key); + private LegacyVpnPreference findOrCreatePreference(VpnProfile profile) { + LegacyVpnPreference pref = mLegacyVpnPreferences.get(profile.key); if (pref == null) { - pref = new ConfigPreference(getPrefContext(), mManageListener); + pref = new LegacyVpnPreference(getPrefContext()); + pref.setOnGearClickListener(mGearListener); pref.setOnPreferenceClickListener(this); - mConfigPreferences.put(profile.key, pref); + mLegacyVpnPreferences.put(profile.key, pref); } pref.setProfile(profile); return pref; @@ -392,7 +398,8 @@ public class VpnSettings extends RestrictedSettingsFragment implements private AppPreference findOrCreatePreference(AppVpnInfo app) { AppPreference pref = mAppPreferences.get(app); if (pref == null) { - pref = new AppPreference(getPrefContext(), mManageListener); + pref = new AppPreference(getPrefContext()); + pref.setOnGearClickListener(mGearListener); pref.setOnPreferenceClickListener(this); mAppPreferences.put(app, pref); } @@ -432,13 +439,13 @@ public class VpnSettings extends RestrictedSettingsFragment implements } @WorkerThread - private Set getReadOnlyUserProfiles() { - Set result = new ArraySet<>(); + private Set getAlwaysOnAppVpnInfos() { + Set result = new ArraySet<>(); for (UserHandle profile : mUserManager.getUserProfiles()) { final int profileId = profile.getIdentifier(); - if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN, profile) - || mConnectivityManager.getAlwaysOnVpnPackageForUser(profileId) != null) { - result.add(profileId); + final String packageName = mConnectivityManager.getAlwaysOnVpnPackageForUser(profileId); + if (packageName != null) { + result.add(new AppVpnInfo(profileId, packageName)); } } return result;