116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang/* 216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * Copyright (C) 2016 The Android Open Source Project 316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * 416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * Licensed under the Apache License, Version 2.0 (the "License"); 516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * you may not use this file except in compliance with the License. 616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * You may obtain a copy of the License at 716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * 816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * http://www.apache.org/licenses/LICENSE-2.0 916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * 1016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * Unless required by applicable law or agreed to in writing, software 1116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * distributed under the License is distributed on an "AS IS" BASIS, 1216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * See the License for the specific language governing permissions and 1416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * limitations under the License. 1516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang */ 1616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changpackage com.android.settings.vpn2; 1716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 1816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.app.AlertDialog; 1916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.app.AppOpsManager; 2016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.app.Dialog; 2116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.app.DialogFragment; 2216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.content.Context; 2316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.content.DialogInterface; 2416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.content.pm.PackageInfo; 2516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.content.pm.PackageManager; 2616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.content.pm.PackageManager.NameNotFoundException; 2716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.net.ConnectivityManager; 28cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Leeimport android.os.Build; 2916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.os.Bundle; 3016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.os.UserHandle; 3116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.os.UserManager; 321b8855b2115f26a418150e3eef9b3773e608b241Victor Changimport android.provider.Settings; 3316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.support.v7.preference.Preference; 3416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport android.util.Log; 3516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 3616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport com.android.internal.logging.MetricsProto.MetricsEvent; 3716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport com.android.internal.net.VpnConfig; 3816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport com.android.settings.R; 3916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport com.android.settings.SettingsPreferenceFragment; 4052541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Leeimport com.android.settings.Utils; 4152541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Leeimport com.android.settingslib.RestrictedLockUtils; 4216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport com.android.settingslib.RestrictedSwitchPreference; 4316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport com.android.settingslib.RestrictedPreference; 4416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 4516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport java.util.List; 4616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 4716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changimport static android.app.AppOpsManager.OP_ACTIVATE_VPN; 4816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 4916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Changpublic class AppManagementFragment extends SettingsPreferenceFragment 5052541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener { 5116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 5216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private static final String TAG = "AppManagementFragment"; 5316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 5416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private static final String ARG_PACKAGE_NAME = "package"; 5516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 5616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private static final String KEY_VERSION = "version"; 5716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private static final String KEY_ALWAYS_ON_VPN = "always_on_vpn"; 5816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private static final String KEY_FORGET_VPN = "forget_vpn"; 5916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 6016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private AppOpsManager mAppOpsManager; 6116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private PackageManager mPackageManager; 6216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private ConnectivityManager mConnectivityManager; 6316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 6416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang // VPN app info 6516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private final int mUserId = UserHandle.myUserId(); 6616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private int mPackageUid; 6716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private String mPackageName; 6816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private PackageInfo mPackageInfo; 6916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private String mVpnLabel; 7016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 7116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang // UI preference 7216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private Preference mPreferenceVersion; 7316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private RestrictedSwitchPreference mPreferenceAlwaysOn; 7416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private RestrictedPreference mPreferenceForget; 7516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 7616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang // Listener 7716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private final AppDialogFragment.Listener mForgetVpnDialogFragmentListener = 7816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang new AppDialogFragment.Listener() { 7916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang @Override 8016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang public void onForget() { 8116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang // Unset always-on-vpn when forgetting the VPN 8216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang if (isVpnAlwaysOn()) { 83fcb0d74a3c107f9bf8165a82850d7a5eef0ca5f3Victor Chang setAlwaysOnVpn(false); 8416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 8516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang // Also dismiss and go back to VPN list 8616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang finish(); 8716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 8816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 8916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang @Override 9016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang public void onCancel() { 9116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang // do nothing 9216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 9316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang }; 9416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 9516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang public static void show(Context context, AppPreference pref) { 9616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang Bundle args = new Bundle(); 9716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang args.putString(ARG_PACKAGE_NAME, pref.getPackageName()); 9816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang Utils.startWithFragmentAsUser(context, AppManagementFragment.class.getName(), args, -1, 9916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang pref.getLabel(), false, new UserHandle(pref.getUserId())); 10016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 10116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 10216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang @Override 10316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang public void onCreate(Bundle savedState) { 10416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang super.onCreate(savedState); 10516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang addPreferencesFromResource(R.xml.vpn_app_management); 10616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 10716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mPackageManager = getContext().getPackageManager(); 10816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mAppOpsManager = getContext().getSystemService(AppOpsManager.class); 10916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mConnectivityManager = getContext().getSystemService(ConnectivityManager.class); 11016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 11116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mPreferenceVersion = findPreference(KEY_VERSION); 11216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mPreferenceAlwaysOn = (RestrictedSwitchPreference) findPreference(KEY_ALWAYS_ON_VPN); 11316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mPreferenceForget = (RestrictedPreference) findPreference(KEY_FORGET_VPN); 11416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 11552541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee mPreferenceAlwaysOn.setOnPreferenceChangeListener(this); 11616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mPreferenceForget.setOnPreferenceClickListener(this); 11716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 11816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 11916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang @Override 12016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang public void onResume() { 12116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang super.onResume(); 12216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 12316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang boolean isInfoLoaded = loadInfo(); 12416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang if (isInfoLoaded) { 12516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mPreferenceVersion.setTitle( 12616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang getPrefContext().getString(R.string.vpn_version, mPackageInfo.versionName)); 12716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang updateUI(); 12816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } else { 12916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang finish(); 13016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 13116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 13216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 13316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang @Override 13416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang public boolean onPreferenceClick(Preference preference) { 13516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang String key = preference.getKey(); 13616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang switch (key) { 13716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang case KEY_FORGET_VPN: 13816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return onForgetVpnClick(); 13916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang default: 14016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang Log.w(TAG, "unknown key is clicked: " + key); 14116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return false; 14216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 14316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 14416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 14516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang @Override 14652541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee public boolean onPreferenceChange(Preference preference, Object newValue) { 14752541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee switch (preference.getKey()) { 14852541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee case KEY_ALWAYS_ON_VPN: 14952541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee return onAlwaysOnVpnClick((Boolean) newValue); 15052541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee default: 15152541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee Log.w(TAG, "unknown key is clicked: " + preference.getKey()); 15252541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee return false; 15352541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee } 15452541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee } 15552541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee 15652541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee @Override 15716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang protected int getMetricsCategory() { 15816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return MetricsEvent.VPN; 15916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 16016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 16116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private boolean onForgetVpnClick() { 162cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee updateRestrictedViews(); 16352541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee if (!mPreferenceForget.isEnabled()) { 16452541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee return false; 16552541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee } 16616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang AppDialogFragment.show(this, mForgetVpnDialogFragmentListener, mPackageInfo, mVpnLabel, 16716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang true /* editing */, true); 16816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return true; 16916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 17016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 17152541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee private boolean onAlwaysOnVpnClick(final boolean isChecked) { 17216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang if (isChecked && isLegacyVpnLockDownOrAnotherPackageAlwaysOn()) { 17316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang // Show dialog if user replace always-on-vpn package and show not checked first 17416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang ReplaceExistingVpnFragment.show(this); 17552541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee return false; 17616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } else { 17752541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee return setAlwaysOnVpnByUI(isChecked); 17816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 17916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 18016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 18152541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee private boolean setAlwaysOnVpnByUI(boolean isEnabled) { 182cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee updateRestrictedViews(); 18352541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee if (!mPreferenceAlwaysOn.isEnabled()) { 18452541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee return false; 18552541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee } 18616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang // Only clear legacy lockdown vpn in system user. 18716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang if (mUserId == UserHandle.USER_SYSTEM) { 18816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang VpnUtils.clearLockdownVpn(getContext()); 18916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 190fcb0d74a3c107f9bf8165a82850d7a5eef0ca5f3Victor Chang final boolean success = setAlwaysOnVpn(isEnabled); 19152541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee if (isEnabled && (!success || !isVpnAlwaysOn())) { 19228210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee CannotConnectFragment.show(this, mVpnLabel); 19328210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee } 19452541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee return success; 19516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 19616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 197fcb0d74a3c107f9bf8165a82850d7a5eef0ca5f3Victor Chang private boolean setAlwaysOnVpn(boolean isEnabled) { 198fcb0d74a3c107f9bf8165a82850d7a5eef0ca5f3Victor Chang return mConnectivityManager.setAlwaysOnVpnPackageForUser(mUserId, 199fcb0d74a3c107f9bf8165a82850d7a5eef0ca5f3Victor Chang isEnabled ? mPackageName : null, /* lockdownEnabled */ false); 200fcb0d74a3c107f9bf8165a82850d7a5eef0ca5f3Victor Chang } 201fcb0d74a3c107f9bf8165a82850d7a5eef0ca5f3Victor Chang 202cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee private boolean checkTargetVersion() { 203cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee if (mPackageInfo == null || mPackageInfo.applicationInfo == null) { 204cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee return true; 205cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee } 206cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee final int targetSdk = mPackageInfo.applicationInfo.targetSdkVersion; 207cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee if (targetSdk >= Build.VERSION_CODES.N) { 208cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee return true; 209cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee } 210cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee if (Log.isLoggable(TAG, Log.DEBUG)) { 211cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee Log.d(TAG, "Package " + mPackageName + " targets SDK version " + targetSdk + "; must" 212cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee + " target at least " + Build.VERSION_CODES.N + " to use always-on."); 213cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee } 214cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee return false; 215cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee } 216cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee 21716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private void updateUI() { 21816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang if (isAdded()) { 21916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mPreferenceAlwaysOn.setChecked(isVpnAlwaysOn()); 220cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee updateRestrictedViews(); 22152541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee } 22252541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee } 22352541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee 224cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee private void updateRestrictedViews() { 22552541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee if (isAdded()) { 22652541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee mPreferenceAlwaysOn.checkRestrictionAndSetDisabled(UserManager.DISALLOW_CONFIG_VPN, 22752541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee mUserId); 22852541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee mPreferenceForget.checkRestrictionAndSetDisabled(UserManager.DISALLOW_CONFIG_VPN, 22952541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee mUserId); 230cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee 23152247f69a579c189a881c53d2d021eeffa1609a8Victor Chang if (checkTargetVersion()) { 23252247f69a579c189a881c53d2d021eeffa1609a8Victor Chang // setSummary doesn't override the admin message when user restriction is applied 23352247f69a579c189a881c53d2d021eeffa1609a8Victor Chang mPreferenceAlwaysOn.setSummary(null); 23452247f69a579c189a881c53d2d021eeffa1609a8Victor Chang // setEnabled is not required here, as checkRestrictionAndSetDisabled 23552247f69a579c189a881c53d2d021eeffa1609a8Victor Chang // should have refreshed the enable state. 23652247f69a579c189a881c53d2d021eeffa1609a8Victor Chang } else { 237cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee mPreferenceAlwaysOn.setEnabled(false); 23852247f69a579c189a881c53d2d021eeffa1609a8Victor Chang mPreferenceAlwaysOn.setSummary(R.string.vpn_not_supported_by_this_app); 239cfc0fb02c1d3ff229323660ca432c23cfc8d11b0Robin Lee } 24016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 24116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 24216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 24316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private String getAlwaysOnVpnPackage() { 24416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return mConnectivityManager.getAlwaysOnVpnPackageForUser(mUserId); 24516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 24616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 24716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private boolean isVpnAlwaysOn() { 24816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return mPackageName.equals(getAlwaysOnVpnPackage()); 24916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 25016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 25116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang /** 25216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * @return false if the intent doesn't contain an existing package or can't retrieve activated 25316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang * vpn info. 25416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang */ 25516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private boolean loadInfo() { 25616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang final Bundle args = getArguments(); 25716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang if (args == null) { 25816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang Log.e(TAG, "empty bundle"); 25916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return false; 26016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 26116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 26216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mPackageName = args.getString(ARG_PACKAGE_NAME); 26316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang if (mPackageName == null) { 26416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang Log.e(TAG, "empty package name"); 26516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return false; 26616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 26716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 26816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang try { 26916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mPackageUid = mPackageManager.getPackageUid(mPackageName, /* PackageInfoFlags */ 0); 27016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mPackageInfo = mPackageManager.getPackageInfo(mPackageName, /* PackageInfoFlags */ 0); 27116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mVpnLabel = VpnConfig.getVpnLabel(getPrefContext(), mPackageName).toString(); 27216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } catch (NameNotFoundException nnfe) { 27316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang Log.e(TAG, "package not found", nnfe); 27416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return false; 27516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 27616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 27716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang if (!isVpnActivated()) { 27816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang Log.e(TAG, "package didn't register VPN profile"); 27916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return false; 28016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 28116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 28216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return true; 28316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 28416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 28516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private boolean isVpnActivated() { 28616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang final List<AppOpsManager.PackageOps> apps = mAppOpsManager.getOpsForPackage(mPackageUid, 28716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang mPackageName, new int[]{OP_ACTIVATE_VPN}); 28816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return apps != null && apps.size() > 0 && apps.get(0) != null; 28916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 29016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 29116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang private boolean isLegacyVpnLockDownOrAnotherPackageAlwaysOn() { 29216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang if (mUserId == UserHandle.USER_SYSTEM) { 29316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang String lockdownKey = VpnUtils.getLockdownVpn(); 29416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang if (lockdownKey != null) { 29516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return true; 29616da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 29716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 29816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 29916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return getAlwaysOnVpnPackage() != null && !isVpnAlwaysOn(); 30016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 30116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 30228210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee public static class CannotConnectFragment extends DialogFragment { 30328210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee private static final String TAG = "CannotConnect"; 30428210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee private static final String ARG_VPN_LABEL = "label"; 30528210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee 30628210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee public static void show(AppManagementFragment parent, String vpnLabel) { 30728210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee if (parent.getFragmentManager().findFragmentByTag(TAG) == null) { 30828210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee final Bundle args = new Bundle(); 30928210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee args.putString(ARG_VPN_LABEL, vpnLabel); 31028210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee 31128210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee final DialogFragment frag = new CannotConnectFragment(); 31228210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee frag.setArguments(args); 31328210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee frag.show(parent.getFragmentManager(), TAG); 3141b8855b2115f26a418150e3eef9b3773e608b241Victor Chang } 3151b8855b2115f26a418150e3eef9b3773e608b241Victor Chang } 3161b8855b2115f26a418150e3eef9b3773e608b241Victor Chang 31728210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee @Override 31828210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee public Dialog onCreateDialog(Bundle savedInstanceState) { 31928210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee final String vpnLabel = getArguments().getString(ARG_VPN_LABEL); 32028210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee return new AlertDialog.Builder(getActivity()) 32128210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee .setTitle(getActivity().getString(R.string.vpn_cant_connect_title, vpnLabel)) 32228210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee .setMessage(getActivity().getString(R.string.vpn_cant_connect_message)) 32328210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee .setPositiveButton(R.string.okay, null) 32428210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee .create(); 32528210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee } 3261b8855b2115f26a418150e3eef9b3773e608b241Victor Chang } 3271b8855b2115f26a418150e3eef9b3773e608b241Victor Chang 32816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang public static class ReplaceExistingVpnFragment extends DialogFragment 32916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang implements DialogInterface.OnClickListener { 33028210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee private static final String TAG = "ReplaceExistingVpn"; 33116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 33216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang public static void show(AppManagementFragment parent) { 33328210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee if (parent.getFragmentManager().findFragmentByTag(TAG) == null) { 33428210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee final ReplaceExistingVpnFragment frag = new ReplaceExistingVpnFragment(); 33528210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee frag.setTargetFragment(parent, 0); 33628210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee frag.show(parent.getFragmentManager(), TAG); 33728210677099c70e0e19f42f2ad3abe5ad78ee8b8Robin Lee } 33816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 33916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 34016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang @Override 34116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang public Dialog onCreateDialog(Bundle savedInstanceState) { 34216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang return new AlertDialog.Builder(getActivity()) 34316da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang .setTitle(R.string.vpn_replace_always_on_vpn_title) 34416da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang .setMessage(getActivity().getString(R.string.vpn_replace_always_on_vpn_message)) 34516da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang .setNegativeButton(getActivity().getString(R.string.vpn_cancel), null) 346c9bf2ac95e346f0c279436aa1f37d5bea6d2443eRobin Lee .setPositiveButton(getActivity().getString(R.string.vpn_replace), this) 34716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang .create(); 34816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 34916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang 35016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang @Override 35116da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang public void onClick(DialogInterface dialog, int which) { 35216da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang if (getTargetFragment() instanceof AppManagementFragment) { 35352541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee final AppManagementFragment target = (AppManagementFragment) getTargetFragment(); 35452541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee if (target.setAlwaysOnVpnByUI(true)) { 35552541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee target.updateUI(); 35652541536d0d4c8f78be26f94fa8f0cf297bde1c4Robin Lee } 35716da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 35816da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 35916da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang } 36016da2aa45000dd32213a3d84baacc82cd2b16e5fVictor Chang} 361