Loading src/com/android/settings/vpn2/AppPreference.java +20 −11 Original line number Diff line number Diff line Loading @@ -39,18 +39,13 @@ public class AppPreference extends ManageablePreference { private int mState = STATE_DISCONNECTED; private String mPackageName; private String mName; private int mUid; private int mUserId = UserHandle.USER_NULL; public AppPreference(Context context, OnClickListener onManage, final String packageName, int uid) { public AppPreference(Context context, OnClickListener onManage) { super(context, null /* attrs */, onManage); mPackageName = packageName; mUid = uid; update(); } public PackageInfo getPackageInfo() { UserHandle user = new UserHandle(UserHandle.getUserId(mUid)); try { PackageManager pm = getUserContext().getPackageManager(); return pm.getPackageInfo(mPackageName, 0 /* flags */); Loading @@ -67,8 +62,18 @@ public class AppPreference extends ManageablePreference { return mPackageName; } public int getUid() { return mUid; public void setPackageName(String name) { mPackageName = name; update(); } public int getUserId() { return mUserId; } public void setUserId(int userId) { mUserId = userId; update(); } public int getState() { Loading @@ -81,6 +86,10 @@ public class AppPreference extends ManageablePreference { } private void update() { if (mPackageName == null || mUserId == UserHandle.USER_NULL) { return; } final String[] states = getContext().getResources().getStringArray(R.array.vpn_states); setSummary(mState != STATE_DISCONNECTED ? states[mState] : ""); Loading Loading @@ -116,7 +125,7 @@ public class AppPreference extends ManageablePreference { } private Context getUserContext() throws PackageManager.NameNotFoundException { UserHandle user = new UserHandle(UserHandle.getUserId(mUid)); UserHandle user = UserHandle.of(mUserId); return getContext().createPackageContextAsUser( getContext().getPackageName(), 0 /* flags */, user); } Loading @@ -128,7 +137,7 @@ public class AppPreference extends ManageablePreference { if ((result = another.mState - mState) == 0 && (result = mName.compareToIgnoreCase(another.mName)) == 0 && (result = mPackageName.compareTo(another.mPackageName)) == 0) { result = mUid - another.mUid; result = mUserId - another.mUserId; } return result; } else if (preference instanceof ConfigPreference) { Loading src/com/android/settings/vpn2/ConfigPreference.java +13 −9 Original line number Diff line number Diff line Loading @@ -31,12 +31,15 @@ import static com.android.internal.net.LegacyVpnInfo.STATE_CONNECTED; * state. */ public class ConfigPreference extends ManageablePreference { public static int STATE_NONE = -1; private VpnProfile mProfile; private int mState = -1; ConfigPreference(Context context, OnClickListener onManage, VpnProfile profile) { /** 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); setProfile(profile); } public VpnProfile getProfile() { Loading @@ -54,15 +57,16 @@ public class ConfigPreference extends ManageablePreference { } private void update() { if (mState < 0) { if (mState == STATE_NONE) { setSummary(""); } else { String[] states = getContext().getResources() .getStringArray(R.array.vpn_states); final String[] states = getContext().getResources().getStringArray(R.array.vpn_states); setSummary(states[mState]); } if (mProfile != null) { setIcon(R.mipmap.ic_launcher_settings); setTitle(mProfile.name); } notifyHierarchyChanged(); } Loading @@ -72,7 +76,7 @@ public class ConfigPreference extends ManageablePreference { ConfigPreference another = (ConfigPreference) preference; int result; if ((result = another.mState - mState) == 0 && (result = mProfile.name.compareTo(another.mProfile.name)) == 0 && (result = mProfile.name.compareToIgnoreCase(another.mProfile.name)) == 0 && (result = mProfile.type - another.mProfile.type) == 0) { result = mProfile.key.compareTo(another.mProfile.key); } Loading src/com/android/settings/vpn2/VpnSettings.java +153 −64 Original line number Diff line number Diff line Loading @@ -16,13 +16,16 @@ package com.android.settings.vpn2; import android.annotation.NonNull; import android.annotation.UiThread; import android.annotation.WorkerThread; import android.app.AppOpsManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; Loading @@ -40,7 +43,9 @@ import android.security.KeyStore; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceScreen; import android.util.SparseArray; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; Loading @@ -57,8 +62,10 @@ import com.android.settings.SettingsPreferenceFragment; import com.google.android.collect.Lists; import java.util.ArrayList; import java.util.HashMap; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import static android.app.AppOpsManager.OP_ACTIVATE_VPN; Loading Loading @@ -87,8 +94,8 @@ public class VpnSettings extends SettingsPreferenceFragment implements private final KeyStore mKeyStore = KeyStore.getInstance(); private HashMap<String, ConfigPreference> mConfigPreferences = new HashMap<>(); private HashMap<String, AppPreference> mAppPreferences = new HashMap<>(); private Map<String, ConfigPreference> mConfigPreferences = new ArrayMap<>(); private Map<AppVpnInfo, AppPreference> mAppPreferences = new ArrayMap<>(); private Handler mUpdater; private LegacyVpnInfo mConnectedLegacyVpn; Loading Loading @@ -211,58 +218,64 @@ public class VpnSettings extends SettingsPreferenceFragment implements public boolean handleMessage(Message message) { mUpdater.removeMessages(RESCAN_MESSAGE); // Pref group within which to list VPNs PreferenceGroup vpnGroup = getPreferenceScreen(); vpnGroup.removeAll(); mConfigPreferences.clear(); mAppPreferences.clear(); final List<VpnProfile> vpnProfiles = loadVpnProfiles(mKeyStore); final List<AppVpnInfo> vpnApps = getVpnApps(); // Fetch configured VPN profiles from KeyStore for (VpnProfile profile : loadVpnProfiles(mKeyStore)) { final ConfigPreference pref = new ConfigPreference(getPrefContext(), mManageListener, profile); pref.setOnPreferenceClickListener(this); mConfigPreferences.put(profile.key, pref); vpnGroup.addPreference(pref); final List<LegacyVpnInfo> connectedLegacyVpns = getConnectedLegacyVpns(); final List<AppVpnInfo> connectedAppVpns = getConnectedAppVpns(); // Refresh the PreferenceGroup which lists VPNs getActivity().runOnUiThread(new Runnable() { @Override public void run() { // Find new VPNs by subtracting existing ones from the full set final Set<Preference> updates = new ArraySet<>(); for (VpnProfile profile : vpnProfiles) { ConfigPreference p = findOrCreatePreference(profile); p.setState(ConfigPreference.STATE_NONE); updates.add(p); } for (AppVpnInfo app : vpnApps) { AppPreference p = findOrCreatePreference(app); p.setState(AppPreference.STATE_DISCONNECTED); updates.add(p); } // 3rd-party VPN apps can change elsewhere. Reload them every time. for (AppOpsManager.PackageOps pkg : getVpnApps()) { String key = getVpnIdentifier(UserHandle.getUserId(pkg.getUid()), pkg.getPackageName()); final AppPreference pref = new AppPreference(getPrefContext(), mManageListener, pkg.getPackageName(), pkg.getUid()); pref.setOnPreferenceClickListener(this); mAppPreferences.put(key, pref); // Trim preferences for deleted VPNs mConfigPreferences.values().retainAll(updates); mAppPreferences.values().retainAll(updates); final PreferenceGroup vpnGroup = getPreferenceScreen(); for (int i = vpnGroup.getPreferenceCount() - 1; i >= 0; i--) { Preference p = vpnGroup.getPreference(i); if (updates.contains(p)) { updates.remove(p); } else { vpnGroup.removePreference(p); } } // Show any new preferences on the screen for (Preference pref : updates) { vpnGroup.addPreference(pref); } // Mark out connections with a subtitle try { // Legacy VPNs mConnectedLegacyVpn = null; LegacyVpnInfo info = mConnectivityService.getLegacyVpnInfo(UserHandle.myUserId()); if (info != null) { ConfigPreference preference = mConfigPreferences.get(info.key); // Mark connected VPNs for (LegacyVpnInfo info : connectedLegacyVpns) { final ConfigPreference preference = mConfigPreferences.get(info.key); if (preference != null) { preference.setState(info.state); mConnectedLegacyVpn = info; } } // Third-party VPNs for (UserHandle profile : mUserManager.getUserProfiles()) { VpnConfig cfg = mConnectivityService.getVpnConfig(profile.getIdentifier()); if (cfg != null) { final String key = getVpnIdentifier(profile.getIdentifier(), cfg.user); final AppPreference preference = mAppPreferences.get(key); for (AppVpnInfo app : connectedAppVpns) { final AppPreference preference = mAppPreferences.get(app); if (preference != null) { preference.setState(AppPreference.STATE_CONNECTED); } } } } catch (RemoteException e) { // ignore } }); mUpdater.sendEmptyMessageDelayed(RESCAN_MESSAGE, RESCAN_INTERVAL_MS); return true; Loading @@ -278,7 +291,7 @@ public class VpnSettings extends SettingsPreferenceFragment implements mConnectedLegacyVpn.intent.send(); return true; } catch (Exception e) { // ignore Log.w(LOG_TAG, "Starting config intent failed", e); } } ConfigDialogFragment.show(this, profile, false /* editing */, true /* exists */); Loading @@ -289,7 +302,7 @@ public class VpnSettings extends SettingsPreferenceFragment implements if (!connected) { try { UserHandle user = new UserHandle(UserHandle.getUserId(pref.getUid())); UserHandle user = UserHandle.of(pref.getUserId()); Context userContext = getActivity().createPackageContextAsUser( getActivity().getPackageName(), 0 /* flags */, user); PackageManager pm = userContext.getPackageManager(); Loading @@ -299,11 +312,11 @@ public class VpnSettings extends SettingsPreferenceFragment implements return true; } } catch (PackageManager.NameNotFoundException nnfe) { // Fall through Log.w(LOG_TAG, "VPN provider does not exist: " + pref.getPackageName(), nnfe); } } // Already onnected or no launch intent available - show an info dialog // Already connected or no launch intent available - show an info dialog PackageInfo pkgInfo = pref.getPackageInfo(); AppDialogFragment.show(this, pkgInfo, pref.getLabel(), false /* editing */, connected); return true; Loading @@ -311,6 +324,11 @@ public class VpnSettings extends SettingsPreferenceFragment implements return false; } @Override protected int getHelpResource() { return R.string.help_url_vpn; } private View.OnClickListener mManageListener = new View.OnClickListener() { @Override public void onClick(View view) { Loading @@ -329,10 +347,6 @@ public class VpnSettings extends SettingsPreferenceFragment implements } }; private static String getVpnIdentifier(int userId, String packageName) { return Integer.toString(userId)+ "_" + packageName; } private NetworkCallback mNetworkCallback = new NetworkCallback() { @Override public void onAvailable(Network network) { Loading @@ -349,18 +363,68 @@ public class VpnSettings extends SettingsPreferenceFragment implements } }; @Override protected int getHelpResource() { return R.string.help_url_vpn; @UiThread private ConfigPreference findOrCreatePreference(VpnProfile profile) { ConfigPreference pref = mConfigPreferences.get(profile.key); if (pref == null) { pref = new ConfigPreference(getPrefContext(), mManageListener); pref.setOnPreferenceClickListener(this); mConfigPreferences.put(profile.key, pref); } pref.setProfile(profile); return pref; } @UiThread private AppPreference findOrCreatePreference(AppVpnInfo app) { AppPreference pref = mAppPreferences.get(app); if (pref == null) { pref = new AppPreference(getPrefContext(), mManageListener); pref.setOnPreferenceClickListener(this); mAppPreferences.put(app, pref); } pref.setUserId(app.userId); pref.setPackageName(app.packageName); return pref; } private List<AppOpsManager.PackageOps> getVpnApps() { List<AppOpsManager.PackageOps> result = Lists.newArrayList(); @WorkerThread private List<LegacyVpnInfo> getConnectedLegacyVpns() { try { mConnectedLegacyVpn = mConnectivityService.getLegacyVpnInfo(UserHandle.myUserId()); if (mConnectedLegacyVpn != null) { return Collections.singletonList(mConnectedLegacyVpn); } } catch (RemoteException e) { Log.e(LOG_TAG, "Failure updating VPN list with connected legacy VPNs", e); } return Collections.emptyList(); } @WorkerThread private List<AppVpnInfo> getConnectedAppVpns() { // Mark connected third-party services List<AppVpnInfo> connections = new ArrayList<>(); try { for (UserHandle profile : mUserManager.getUserProfiles()) { VpnConfig config = mConnectivityService.getVpnConfig(profile.getIdentifier()); if (config != null && !config.legacy) { connections.add(new AppVpnInfo(profile.getIdentifier(), config.user)); } } } catch (RemoteException e) { Log.e(LOG_TAG, "Failure updating VPN list with connected app VPNs", e); } return connections; } private List<AppVpnInfo> getVpnApps() { List<AppVpnInfo> result = Lists.newArrayList(); // Build a filter of currently active user profiles. SparseArray<Boolean> currentProfileIds = new SparseArray<>(); Set<Integer> currentProfileIds = new ArraySet<>(); for (UserHandle profile : mUserManager.getUserProfiles()) { currentProfileIds.put(profile.getIdentifier(), Boolean.TRUE); currentProfileIds.add(profile.getIdentifier()); } // Fetch VPN-enabled apps from AppOps. Loading @@ -369,7 +433,7 @@ public class VpnSettings extends SettingsPreferenceFragment implements if (apps != null) { for (AppOpsManager.PackageOps pkg : apps) { int userId = UserHandle.getUserId(pkg.getUid()); if (currentProfileIds.get(userId) == null) { if (!currentProfileIds.contains(userId)) { // Skip packages for users outside of our profile group. continue; } Loading @@ -382,7 +446,7 @@ public class VpnSettings extends SettingsPreferenceFragment implements } } if (allowed) { result.add(pkg); result.add(new AppVpnInfo(userId, pkg.getPackageName())); } } } Loading @@ -407,4 +471,29 @@ public class VpnSettings extends SettingsPreferenceFragment implements } return result; } /** Utility holder for packageName:userId pairs */ private static class AppVpnInfo { public int userId; public String packageName; public AppVpnInfo(int userId, @NonNull String packageName) { this.userId = userId; this.packageName = packageName; } @Override public boolean equals(Object other) { if (other instanceof AppVpnInfo) { AppVpnInfo that = (AppVpnInfo) other; return userId == that.userId && packageName.equals(that.packageName); } return false; } @Override public int hashCode() { return (packageName != null ? packageName.hashCode() : 0) * 31 + userId; } } } Loading
src/com/android/settings/vpn2/AppPreference.java +20 −11 Original line number Diff line number Diff line Loading @@ -39,18 +39,13 @@ public class AppPreference extends ManageablePreference { private int mState = STATE_DISCONNECTED; private String mPackageName; private String mName; private int mUid; private int mUserId = UserHandle.USER_NULL; public AppPreference(Context context, OnClickListener onManage, final String packageName, int uid) { public AppPreference(Context context, OnClickListener onManage) { super(context, null /* attrs */, onManage); mPackageName = packageName; mUid = uid; update(); } public PackageInfo getPackageInfo() { UserHandle user = new UserHandle(UserHandle.getUserId(mUid)); try { PackageManager pm = getUserContext().getPackageManager(); return pm.getPackageInfo(mPackageName, 0 /* flags */); Loading @@ -67,8 +62,18 @@ public class AppPreference extends ManageablePreference { return mPackageName; } public int getUid() { return mUid; public void setPackageName(String name) { mPackageName = name; update(); } public int getUserId() { return mUserId; } public void setUserId(int userId) { mUserId = userId; update(); } public int getState() { Loading @@ -81,6 +86,10 @@ public class AppPreference extends ManageablePreference { } private void update() { if (mPackageName == null || mUserId == UserHandle.USER_NULL) { return; } final String[] states = getContext().getResources().getStringArray(R.array.vpn_states); setSummary(mState != STATE_DISCONNECTED ? states[mState] : ""); Loading Loading @@ -116,7 +125,7 @@ public class AppPreference extends ManageablePreference { } private Context getUserContext() throws PackageManager.NameNotFoundException { UserHandle user = new UserHandle(UserHandle.getUserId(mUid)); UserHandle user = UserHandle.of(mUserId); return getContext().createPackageContextAsUser( getContext().getPackageName(), 0 /* flags */, user); } Loading @@ -128,7 +137,7 @@ public class AppPreference extends ManageablePreference { if ((result = another.mState - mState) == 0 && (result = mName.compareToIgnoreCase(another.mName)) == 0 && (result = mPackageName.compareTo(another.mPackageName)) == 0) { result = mUid - another.mUid; result = mUserId - another.mUserId; } return result; } else if (preference instanceof ConfigPreference) { Loading
src/com/android/settings/vpn2/ConfigPreference.java +13 −9 Original line number Diff line number Diff line Loading @@ -31,12 +31,15 @@ import static com.android.internal.net.LegacyVpnInfo.STATE_CONNECTED; * state. */ public class ConfigPreference extends ManageablePreference { public static int STATE_NONE = -1; private VpnProfile mProfile; private int mState = -1; ConfigPreference(Context context, OnClickListener onManage, VpnProfile profile) { /** 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); setProfile(profile); } public VpnProfile getProfile() { Loading @@ -54,15 +57,16 @@ public class ConfigPreference extends ManageablePreference { } private void update() { if (mState < 0) { if (mState == STATE_NONE) { setSummary(""); } else { String[] states = getContext().getResources() .getStringArray(R.array.vpn_states); final String[] states = getContext().getResources().getStringArray(R.array.vpn_states); setSummary(states[mState]); } if (mProfile != null) { setIcon(R.mipmap.ic_launcher_settings); setTitle(mProfile.name); } notifyHierarchyChanged(); } Loading @@ -72,7 +76,7 @@ public class ConfigPreference extends ManageablePreference { ConfigPreference another = (ConfigPreference) preference; int result; if ((result = another.mState - mState) == 0 && (result = mProfile.name.compareTo(another.mProfile.name)) == 0 && (result = mProfile.name.compareToIgnoreCase(another.mProfile.name)) == 0 && (result = mProfile.type - another.mProfile.type) == 0) { result = mProfile.key.compareTo(another.mProfile.key); } Loading
src/com/android/settings/vpn2/VpnSettings.java +153 −64 Original line number Diff line number Diff line Loading @@ -16,13 +16,16 @@ package com.android.settings.vpn2; import android.annotation.NonNull; import android.annotation.UiThread; import android.annotation.WorkerThread; import android.app.AppOpsManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; Loading @@ -40,7 +43,9 @@ import android.security.KeyStore; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceScreen; import android.util.SparseArray; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; Loading @@ -57,8 +62,10 @@ import com.android.settings.SettingsPreferenceFragment; import com.google.android.collect.Lists; import java.util.ArrayList; import java.util.HashMap; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import static android.app.AppOpsManager.OP_ACTIVATE_VPN; Loading Loading @@ -87,8 +94,8 @@ public class VpnSettings extends SettingsPreferenceFragment implements private final KeyStore mKeyStore = KeyStore.getInstance(); private HashMap<String, ConfigPreference> mConfigPreferences = new HashMap<>(); private HashMap<String, AppPreference> mAppPreferences = new HashMap<>(); private Map<String, ConfigPreference> mConfigPreferences = new ArrayMap<>(); private Map<AppVpnInfo, AppPreference> mAppPreferences = new ArrayMap<>(); private Handler mUpdater; private LegacyVpnInfo mConnectedLegacyVpn; Loading Loading @@ -211,58 +218,64 @@ public class VpnSettings extends SettingsPreferenceFragment implements public boolean handleMessage(Message message) { mUpdater.removeMessages(RESCAN_MESSAGE); // Pref group within which to list VPNs PreferenceGroup vpnGroup = getPreferenceScreen(); vpnGroup.removeAll(); mConfigPreferences.clear(); mAppPreferences.clear(); final List<VpnProfile> vpnProfiles = loadVpnProfiles(mKeyStore); final List<AppVpnInfo> vpnApps = getVpnApps(); // Fetch configured VPN profiles from KeyStore for (VpnProfile profile : loadVpnProfiles(mKeyStore)) { final ConfigPreference pref = new ConfigPreference(getPrefContext(), mManageListener, profile); pref.setOnPreferenceClickListener(this); mConfigPreferences.put(profile.key, pref); vpnGroup.addPreference(pref); final List<LegacyVpnInfo> connectedLegacyVpns = getConnectedLegacyVpns(); final List<AppVpnInfo> connectedAppVpns = getConnectedAppVpns(); // Refresh the PreferenceGroup which lists VPNs getActivity().runOnUiThread(new Runnable() { @Override public void run() { // Find new VPNs by subtracting existing ones from the full set final Set<Preference> updates = new ArraySet<>(); for (VpnProfile profile : vpnProfiles) { ConfigPreference p = findOrCreatePreference(profile); p.setState(ConfigPreference.STATE_NONE); updates.add(p); } for (AppVpnInfo app : vpnApps) { AppPreference p = findOrCreatePreference(app); p.setState(AppPreference.STATE_DISCONNECTED); updates.add(p); } // 3rd-party VPN apps can change elsewhere. Reload them every time. for (AppOpsManager.PackageOps pkg : getVpnApps()) { String key = getVpnIdentifier(UserHandle.getUserId(pkg.getUid()), pkg.getPackageName()); final AppPreference pref = new AppPreference(getPrefContext(), mManageListener, pkg.getPackageName(), pkg.getUid()); pref.setOnPreferenceClickListener(this); mAppPreferences.put(key, pref); // Trim preferences for deleted VPNs mConfigPreferences.values().retainAll(updates); mAppPreferences.values().retainAll(updates); final PreferenceGroup vpnGroup = getPreferenceScreen(); for (int i = vpnGroup.getPreferenceCount() - 1; i >= 0; i--) { Preference p = vpnGroup.getPreference(i); if (updates.contains(p)) { updates.remove(p); } else { vpnGroup.removePreference(p); } } // Show any new preferences on the screen for (Preference pref : updates) { vpnGroup.addPreference(pref); } // Mark out connections with a subtitle try { // Legacy VPNs mConnectedLegacyVpn = null; LegacyVpnInfo info = mConnectivityService.getLegacyVpnInfo(UserHandle.myUserId()); if (info != null) { ConfigPreference preference = mConfigPreferences.get(info.key); // Mark connected VPNs for (LegacyVpnInfo info : connectedLegacyVpns) { final ConfigPreference preference = mConfigPreferences.get(info.key); if (preference != null) { preference.setState(info.state); mConnectedLegacyVpn = info; } } // Third-party VPNs for (UserHandle profile : mUserManager.getUserProfiles()) { VpnConfig cfg = mConnectivityService.getVpnConfig(profile.getIdentifier()); if (cfg != null) { final String key = getVpnIdentifier(profile.getIdentifier(), cfg.user); final AppPreference preference = mAppPreferences.get(key); for (AppVpnInfo app : connectedAppVpns) { final AppPreference preference = mAppPreferences.get(app); if (preference != null) { preference.setState(AppPreference.STATE_CONNECTED); } } } } catch (RemoteException e) { // ignore } }); mUpdater.sendEmptyMessageDelayed(RESCAN_MESSAGE, RESCAN_INTERVAL_MS); return true; Loading @@ -278,7 +291,7 @@ public class VpnSettings extends SettingsPreferenceFragment implements mConnectedLegacyVpn.intent.send(); return true; } catch (Exception e) { // ignore Log.w(LOG_TAG, "Starting config intent failed", e); } } ConfigDialogFragment.show(this, profile, false /* editing */, true /* exists */); Loading @@ -289,7 +302,7 @@ public class VpnSettings extends SettingsPreferenceFragment implements if (!connected) { try { UserHandle user = new UserHandle(UserHandle.getUserId(pref.getUid())); UserHandle user = UserHandle.of(pref.getUserId()); Context userContext = getActivity().createPackageContextAsUser( getActivity().getPackageName(), 0 /* flags */, user); PackageManager pm = userContext.getPackageManager(); Loading @@ -299,11 +312,11 @@ public class VpnSettings extends SettingsPreferenceFragment implements return true; } } catch (PackageManager.NameNotFoundException nnfe) { // Fall through Log.w(LOG_TAG, "VPN provider does not exist: " + pref.getPackageName(), nnfe); } } // Already onnected or no launch intent available - show an info dialog // Already connected or no launch intent available - show an info dialog PackageInfo pkgInfo = pref.getPackageInfo(); AppDialogFragment.show(this, pkgInfo, pref.getLabel(), false /* editing */, connected); return true; Loading @@ -311,6 +324,11 @@ public class VpnSettings extends SettingsPreferenceFragment implements return false; } @Override protected int getHelpResource() { return R.string.help_url_vpn; } private View.OnClickListener mManageListener = new View.OnClickListener() { @Override public void onClick(View view) { Loading @@ -329,10 +347,6 @@ public class VpnSettings extends SettingsPreferenceFragment implements } }; private static String getVpnIdentifier(int userId, String packageName) { return Integer.toString(userId)+ "_" + packageName; } private NetworkCallback mNetworkCallback = new NetworkCallback() { @Override public void onAvailable(Network network) { Loading @@ -349,18 +363,68 @@ public class VpnSettings extends SettingsPreferenceFragment implements } }; @Override protected int getHelpResource() { return R.string.help_url_vpn; @UiThread private ConfigPreference findOrCreatePreference(VpnProfile profile) { ConfigPreference pref = mConfigPreferences.get(profile.key); if (pref == null) { pref = new ConfigPreference(getPrefContext(), mManageListener); pref.setOnPreferenceClickListener(this); mConfigPreferences.put(profile.key, pref); } pref.setProfile(profile); return pref; } @UiThread private AppPreference findOrCreatePreference(AppVpnInfo app) { AppPreference pref = mAppPreferences.get(app); if (pref == null) { pref = new AppPreference(getPrefContext(), mManageListener); pref.setOnPreferenceClickListener(this); mAppPreferences.put(app, pref); } pref.setUserId(app.userId); pref.setPackageName(app.packageName); return pref; } private List<AppOpsManager.PackageOps> getVpnApps() { List<AppOpsManager.PackageOps> result = Lists.newArrayList(); @WorkerThread private List<LegacyVpnInfo> getConnectedLegacyVpns() { try { mConnectedLegacyVpn = mConnectivityService.getLegacyVpnInfo(UserHandle.myUserId()); if (mConnectedLegacyVpn != null) { return Collections.singletonList(mConnectedLegacyVpn); } } catch (RemoteException e) { Log.e(LOG_TAG, "Failure updating VPN list with connected legacy VPNs", e); } return Collections.emptyList(); } @WorkerThread private List<AppVpnInfo> getConnectedAppVpns() { // Mark connected third-party services List<AppVpnInfo> connections = new ArrayList<>(); try { for (UserHandle profile : mUserManager.getUserProfiles()) { VpnConfig config = mConnectivityService.getVpnConfig(profile.getIdentifier()); if (config != null && !config.legacy) { connections.add(new AppVpnInfo(profile.getIdentifier(), config.user)); } } } catch (RemoteException e) { Log.e(LOG_TAG, "Failure updating VPN list with connected app VPNs", e); } return connections; } private List<AppVpnInfo> getVpnApps() { List<AppVpnInfo> result = Lists.newArrayList(); // Build a filter of currently active user profiles. SparseArray<Boolean> currentProfileIds = new SparseArray<>(); Set<Integer> currentProfileIds = new ArraySet<>(); for (UserHandle profile : mUserManager.getUserProfiles()) { currentProfileIds.put(profile.getIdentifier(), Boolean.TRUE); currentProfileIds.add(profile.getIdentifier()); } // Fetch VPN-enabled apps from AppOps. Loading @@ -369,7 +433,7 @@ public class VpnSettings extends SettingsPreferenceFragment implements if (apps != null) { for (AppOpsManager.PackageOps pkg : apps) { int userId = UserHandle.getUserId(pkg.getUid()); if (currentProfileIds.get(userId) == null) { if (!currentProfileIds.contains(userId)) { // Skip packages for users outside of our profile group. continue; } Loading @@ -382,7 +446,7 @@ public class VpnSettings extends SettingsPreferenceFragment implements } } if (allowed) { result.add(pkg); result.add(new AppVpnInfo(userId, pkg.getPackageName())); } } } Loading @@ -407,4 +471,29 @@ public class VpnSettings extends SettingsPreferenceFragment implements } return result; } /** Utility holder for packageName:userId pairs */ private static class AppVpnInfo { public int userId; public String packageName; public AppVpnInfo(int userId, @NonNull String packageName) { this.userId = userId; this.packageName = packageName; } @Override public boolean equals(Object other) { if (other instanceof AppVpnInfo) { AppVpnInfo that = (AppVpnInfo) other; return userId == that.userId && packageName.equals(that.packageName); } return false; } @Override public int hashCode() { return (packageName != null ? packageName.hashCode() : 0) * 31 + userId; } } }