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 75be5d46823..58c6005592d 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;