diff options
Diffstat (limited to 'src/com/android/settings')
3 files changed, 138 insertions, 8 deletions
diff --git a/src/com/android/settings/network/MobileNetworkPreferenceController.java b/src/com/android/settings/network/MobileNetworkPreferenceController.java index f55e753ac3..c7abf905cd 100644 --- a/src/com/android/settings/network/MobileNetworkPreferenceController.java +++ b/src/com/android/settings/network/MobileNetworkPreferenceController.java @@ -26,7 +26,6 @@ import android.telephony.TelephonyManager; import com.android.settings.Utils; import com.android.settings.core.PreferenceController; -import com.android.settings.core.lifecycle.Lifecycle; import com.android.settings.core.lifecycle.LifecycleObserver; import com.android.settings.core.lifecycle.events.OnPause; import com.android.settings.core.lifecycle.events.OnResume; diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java index 9a811b86db..f52230b61d 100644 --- a/src/com/android/settings/network/NetworkDashboardFragment.java +++ b/src/com/android/settings/network/NetworkDashboardFragment.java @@ -83,17 +83,20 @@ public class NetworkDashboardFragment extends DashboardFragment implements new WifiMasterSwitchPreferenceController(context, mMetricsFeatureProvider); final MobileNetworkPreferenceController mobileNetworkPreferenceController = new MobileNetworkPreferenceController(context); + final VpnPreferenceController vpnPreferenceController = + new VpnPreferenceController(context); final Lifecycle lifecycle = getLifecycle(); lifecycle.addObserver(airplaneModePreferenceController); lifecycle.addObserver(mobilePlanPreferenceController); lifecycle.addObserver(wifiPreferenceController); lifecycle.addObserver(mobileNetworkPreferenceController); + lifecycle.addObserver(vpnPreferenceController); final List<PreferenceController> controllers = new ArrayList<>(); controllers.add(airplaneModePreferenceController); controllers.add(mobileNetworkPreferenceController); controllers.add(new TetherPreferenceController(context)); - controllers.add(new VpnPreferenceController(context)); + controllers.add(vpnPreferenceController); controllers.add(new ProxyPreferenceController(context)); controllers.add(mobilePlanPreferenceController); controllers.add(wifiPreferenceController); diff --git a/src/com/android/settings/network/VpnPreferenceController.java b/src/com/android/settings/network/VpnPreferenceController.java index f7e230ffd0..86ff175412 100644 --- a/src/com/android/settings/network/VpnPreferenceController.java +++ b/src/com/android/settings/network/VpnPreferenceController.java @@ -16,38 +16,74 @@ package com.android.settings.network; import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.UserInfo; +import android.net.ConnectivityManager; +import android.net.IConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.support.annotation.VisibleForTesting; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; +import android.util.Log; +import android.util.SparseArray; +import com.android.internal.net.LegacyVpnInfo; +import com.android.internal.net.VpnConfig; +import com.android.settings.R; import com.android.settings.core.PreferenceController; +import com.android.settings.core.lifecycle.LifecycleObserver; +import com.android.settings.core.lifecycle.events.OnPause; +import com.android.settings.core.lifecycle.events.OnResume; import com.android.settingslib.RestrictedLockUtils; +import java.util.List; -public class VpnPreferenceController extends PreferenceController { + +public class VpnPreferenceController extends PreferenceController implements LifecycleObserver, + OnResume, OnPause { private static final String KEY_VPN_SETTINGS = "vpn_settings"; + private static final NetworkRequest REQUEST = new NetworkRequest.Builder() + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .build(); + private static final String TAG = "VpnPreferenceController"; private final String mToggleable; - private final boolean mIsSecondaryUser; + private final UserManager mUserManager; + private final ConnectivityManager mConnectivityManager; + private final IConnectivityManager mConnectivityManagerService; + private Preference mPreference; public VpnPreferenceController(Context context) { super(context); mToggleable = Settings.Global.getString(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); - mIsSecondaryUser = !UserManager.get(context).isAdminUser(); + mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + mConnectivityManager = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + mConnectivityManagerService = IConnectivityManager.Stub.asInterface( + ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); } @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); + mPreference = screen.findPreference(KEY_VPN_SETTINGS); // Manually set dependencies for Wifi when not toggleable. if (mToggleable == null || !mToggleable.contains(Settings.Global.RADIO_WIFI)) { - final Preference pref = screen.findPreference(KEY_VPN_SETTINGS); - if (pref != null) { - pref.setDependency(AirplaneModePreferenceController.KEY_TOGGLE_AIRPLANE); + if (mPreference != null) { + mPreference.setDependency(AirplaneModePreferenceController.KEY_TOGGLE_AIRPLANE); } } } @@ -62,4 +98,96 @@ public class VpnPreferenceController extends PreferenceController { public String getPreferenceKey() { return KEY_VPN_SETTINGS; } + + @Override + public void onPause() { + if (isAvailable()) { + mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); + } + } + + @Override + public void onResume() { + if (isAvailable()) { + mConnectivityManager.registerNetworkCallback(REQUEST, mNetworkCallback); + } + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + void updateSummary() { + if (mPreference == null) { + return; + } + // Copied from SystemUI::SecurityControllerImpl + SparseArray<VpnConfig> vpns = new SparseArray<>(); + try { + final List<UserInfo> users = mUserManager.getUsers(); + for (UserInfo user : users) { + VpnConfig cfg = mConnectivityManagerService.getVpnConfig(user.id); + if (cfg == null) { + continue; + } else if (cfg.legacy) { + // Legacy VPNs should do nothing if the network is disconnected. Third-party + // VPN warnings need to continue as traffic can still go to the app. + final LegacyVpnInfo legacyVpn = + mConnectivityManagerService.getLegacyVpnInfo(user.id); + if (legacyVpn == null || legacyVpn.state != LegacyVpnInfo.STATE_CONNECTED) { + continue; + } + } + vpns.put(user.id, cfg); + } + } catch (RemoteException rme) { + // Roll back to previous state + Log.e(TAG, "Unable to list active VPNs", rme); + return; + } + final UserInfo userInfo = mUserManager.getUserInfo(UserHandle.myUserId()); + final int uid; + if (userInfo.isRestricted()) { + uid = userInfo.restrictedProfileParentId; + } else { + uid = userInfo.id; + } + VpnConfig vpn = vpns.get(uid); + final String vpnName; + if (vpn == null) { + vpnName = null; + } else { + vpnName = getNameForVpnConfig(vpn, UserHandle.of(uid)); + } + new Handler(Looper.getMainLooper()).post(() -> mPreference.setSummary(vpnName)); + } + + private String getNameForVpnConfig(VpnConfig cfg, UserHandle user) { + if (cfg.legacy) { + return mContext.getString(R.string.bluetooth_connected); + } + // The package name for an active VPN is stored in the 'user' field of its VpnConfig + final String vpnPackage = cfg.user; + try { + Context userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), + 0 /* flags */, user); + return VpnConfig.getVpnLabel(userContext, vpnPackage).toString(); + } catch (PackageManager.NameNotFoundException nnfe) { + Log.e(TAG, "Package " + vpnPackage + " is not present", nnfe); + return null; + } + } + + // Copied from SystemUI::SecurityControllerImpl + private final ConnectivityManager.NetworkCallback + mNetworkCallback = new ConnectivityManager.NetworkCallback() { + @Override + public void onAvailable(Network network) { + Log.d(TAG, "onAvailable " + network.netId); + updateSummary(); + } + + @Override + public void onLost(Network network) { + Log.d(TAG, "onLost " + network.netId); + updateSummary(); + } + }; } |