VpnSettings.java revision 8b78299d94ebb09fb9bf2bc7fb0015d2f1950839
1310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh/* 2310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * Copyright (C) 2011 The Android Open Source Project 3310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * 4310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License"); 5310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * you may not use this file except in compliance with the License. 6310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * You may obtain a copy of the License at 7310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * 8310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * http://www.apache.org/licenses/LICENSE-2.0 9310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * 10310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software 11310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS, 12310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * See the License for the specific language governing permissions and 14310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh * limitations under the License. 15310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh */ 16310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 17310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehpackage com.android.settings.vpn2; 18310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 199fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport android.app.AlertDialog; 209fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport android.app.Dialog; 219fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport android.app.DialogFragment; 22310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.content.Context; 23310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.content.DialogInterface; 249fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport android.content.res.Resources; 259fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport android.net.ConnectivityManager; 26bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yehimport android.net.IConnectivityManager; 27310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.os.Bundle; 28310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.os.Handler; 29310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.os.Message; 30bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yehimport android.os.ServiceManager; 3107d465ddb8629f128dde193d22de28cfd56663caJeff Sharkeyimport android.os.SystemProperties; 32310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.preference.Preference; 33310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.preference.PreferenceGroup; 34310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.security.Credentials; 35310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.security.KeyStore; 369fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport android.text.TextUtils; 37310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.util.Log; 38310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.view.ContextMenu; 39310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.view.ContextMenu.ContextMenuInfo; 409fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport android.view.LayoutInflater; 41310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.view.Menu; 429fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport android.view.MenuInflater; 43310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.view.MenuItem; 44310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.view.View; 45310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport android.widget.AdapterView.AdapterContextMenuInfo; 469fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport android.widget.ArrayAdapter; 479fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport android.widget.ListView; 4894cc1bbf3218a020548a90032ec34f608f4cefdbChia-chi Yehimport android.widget.Toast; 49310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 5097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yehimport com.android.internal.net.LegacyVpnInfo; 51d95ec871138ebb367cfd8b67b4814438ac30c628Chia-chi Yehimport com.android.internal.net.VpnConfig; 52c6e84c09590ec5e4da287fba32dd53775156ae76Jeff Sharkeyimport com.android.internal.net.VpnProfile; 53f5de1db28a61d159e62ef42f64a2cdcb316d0c2cJeff Sharkeyimport com.android.internal.util.ArrayUtils; 54745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkeyimport com.android.settings.R; 55310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport com.android.settings.SettingsPreferenceFragment; 569fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport com.google.android.collect.Lists; 57310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 589fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport java.util.ArrayList; 59310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehimport java.util.HashMap; 609fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkeyimport java.util.List; 61310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 62310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yehpublic class VpnSettings extends SettingsPreferenceFragment implements 63310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Handler.Callback, Preference.OnPreferenceClickListener, 64310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh DialogInterface.OnClickListener, DialogInterface.OnDismissListener { 65310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private static final String TAG = "VpnSettings"; 66310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 679fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private static final String TAG_LOCKDOWN = "lockdown"; 689fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 698b78299d94ebb09fb9bf2bc7fb0015d2f1950839Jeff Sharkey private static final String EXTRA_PICK_LOCKDOWN = "android.net.vpn.PICK_LOCKDOWN"; 708b78299d94ebb09fb9bf2bc7fb0015d2f1950839Jeff Sharkey 719fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey // TODO: migrate to using DialogFragment when editing 729fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 7397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh private final IConnectivityManager mService = IConnectivityManager.Stub 7497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh .asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); 75310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private final KeyStore mKeyStore = KeyStore.getInstance(); 76310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private boolean mUnlocking = false; 77310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 7888b0140241c646c87d356748621cef28a3105466Robert Greenwalt private HashMap<String, VpnPreference> mPreferences = new HashMap<String, VpnPreference>(); 79310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private VpnDialog mDialog; 80bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh 81bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh private Handler mUpdater; 8297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh private LegacyVpnInfo mInfo; 83bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh 84bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh // The key of the profile for the current ContextMenu. 85310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private String mSelectedKey; 86310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 87310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 88310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onCreate(Bundle savedState) { 89310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh super.onCreate(savedState); 909fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 919fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey setHasOptionsMenu(true); 92310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh addPreferencesFromResource(R.xml.vpn_settings2); 93310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 948b78299d94ebb09fb9bf2bc7fb0015d2f1950839Jeff Sharkey final boolean pickLockdown = getActivity() 958b78299d94ebb09fb9bf2bc7fb0015d2f1950839Jeff Sharkey .getIntent().getBooleanExtra(EXTRA_PICK_LOCKDOWN, false); 968b78299d94ebb09fb9bf2bc7fb0015d2f1950839Jeff Sharkey if (pickLockdown) { 978b78299d94ebb09fb9bf2bc7fb0015d2f1950839Jeff Sharkey LockdownConfigFragment.show(this); 988b78299d94ebb09fb9bf2bc7fb0015d2f1950839Jeff Sharkey } 998b78299d94ebb09fb9bf2bc7fb0015d2f1950839Jeff Sharkey 100310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (savedState != null) { 101310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile profile = VpnProfile.decode(savedState.getString("VpnKey"), 102310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.getByteArray("VpnProfile")); 103310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (profile != null) { 104310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog = new VpnDialog(getActivity(), this, profile, 105310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.getBoolean("VpnEditing")); 106310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 107310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 108310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 109310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 110310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 1119fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 1129fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey super.onCreateOptionsMenu(menu, inflater); 1139fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey inflater.inflate(R.menu.vpn, menu); 1149fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1159fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 1169fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey @Override 11707d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey public void onPrepareOptionsMenu(Menu menu) { 11807d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey super.onPrepareOptionsMenu(menu); 11907d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey 12007d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey // Hide lockdown VPN on devices that require IMS authentication 12107d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey if (SystemProperties.getBoolean("persist.radio.imsregrequired", false)) { 12207d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey menu.findItem(R.id.vpn_lockdown).setVisible(false); 12307d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey } 12407d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey } 12507d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey 12607d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey @Override 1279fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public boolean onOptionsItemSelected(MenuItem item) { 1289fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey switch (item.getItemId()) { 1299fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey case R.id.vpn_create: { 1309fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey // Generate a new key. Here we just use the current time. 1319fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey long millis = System.currentTimeMillis(); 1329fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey while (mPreferences.containsKey(Long.toHexString(millis))) { 1339fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey ++millis; 1349fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1359fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mDialog = new VpnDialog( 1369fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey getActivity(), this, new VpnProfile(Long.toHexString(millis)), true); 1379fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mDialog.setOnDismissListener(this); 1389fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mDialog.show(); 1399fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return true; 1409fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1419fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey case R.id.vpn_lockdown: { 1429fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey LockdownConfigFragment.show(this); 1439fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return true; 1449fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1459fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1469fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return super.onOptionsItemSelected(item); 1479fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1489fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 1499fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey @Override 150310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onSaveInstanceState(Bundle savedState) { 151310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // We do not save view hierarchy, as they are just profiles. 152310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 153310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile profile = mDialog.getProfile(); 154310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.putString("VpnKey", profile.key); 155310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.putByteArray("VpnProfile", profile.encode()); 156310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.putBoolean("VpnEditing", mDialog.isEditing()); 157310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 158310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // else? 159310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 160310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 161310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 162310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onResume() { 163310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh super.onResume(); 164310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 165310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Check KeyStore here, so others do not need to deal with it. 166ca714d8d0c11c904b25bc20a0a9b2f2cc8d78ad5Kenny Root if (!mKeyStore.isUnlocked()) { 167310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (!mUnlocking) { 168310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Let us unlock KeyStore. See you later! 169310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Credentials.getInstance().unlock(getActivity()); 170310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } else { 171310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // We already tried, but it is still not working! 172d68dbe29bb0a6639bfd95449eb28e7d4b174a3feChia-chi Yeh finishFragment(); 173310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 174310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mUnlocking = !mUnlocking; 175310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return; 176310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 177310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 178310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Now KeyStore is always unlocked. Reset the flag. 179310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mUnlocking = false; 180310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 181310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Currently we are the only user of profiles in KeyStore. 182310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Assuming KeyStore and KeyGuard do the right thing, we can 183310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // safely cache profiles in the memory. 18488b0140241c646c87d356748621cef28a3105466Robert Greenwalt if (mPreferences.size() == 0) { 185d501b5c963c0cbcc9c666f502229599464eaf3fdChia-chi Yeh PreferenceGroup group = getPreferenceScreen(); 186310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 1879fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final Context context = getActivity(); 1889fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final List<VpnProfile> profiles = loadVpnProfiles(mKeyStore); 1899fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey for (VpnProfile profile : profiles) { 1909fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final VpnPreference pref = new VpnPreference(context, profile); 1919fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey pref.setOnPreferenceClickListener(this); 1929fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mPreferences.put(profile.key, pref); 1939fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey group.addPreference(pref); 194310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 195310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 196310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 197310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Show the dialog if there is one. 198310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 199310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.setOnDismissListener(this); 200310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.show(); 201310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 202310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 203310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Start monitoring. 204bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh if (mUpdater == null) { 205bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh mUpdater = new Handler(this); 206310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 207bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh mUpdater.sendEmptyMessage(0); 208310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 209310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Register for context menu. Hmmm, getListView() is hidden? 210310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh registerForContextMenu(getListView()); 211310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 212310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 213310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 214310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onPause() { 215310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh super.onPause(); 216310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 217310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Hide the dialog if there is one. 218310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 219310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.setOnDismissListener(null); 220310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.dismiss(); 221310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 222310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 223310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Unregister for context menu. 2246d4334be691815cd9615b0fdebb756999a9c06a3Chia-chi Yeh if (getView() != null) { 2256d4334be691815cd9615b0fdebb756999a9c06a3Chia-chi Yeh unregisterForContextMenu(getListView()); 2266d4334be691815cd9615b0fdebb756999a9c06a3Chia-chi Yeh } 227310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 228310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 229310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 230310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onDismiss(DialogInterface dialog) { 231310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Here is the exit of a dialog. 232310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog = null; 233310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 234310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 235310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 236310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onClick(DialogInterface dialog, int button) { 237310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (button == DialogInterface.BUTTON_POSITIVE) { 238310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Always save the profile. 239310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile profile = mDialog.getProfile(); 240310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mKeyStore.put(Credentials.VPN + profile.key, profile.encode()); 241310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 242310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Update the preference. 243310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnPreference preference = mPreferences.get(profile.key); 244310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference != null) { 245310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh disconnect(profile.key); 246310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh preference.update(profile); 247310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } else { 248310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh preference = new VpnPreference(getActivity(), profile); 2499fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey preference.setOnPreferenceClickListener(this); 250310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mPreferences.put(profile.key, preference); 251310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh getPreferenceScreen().addPreference(preference); 252310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 253310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 254310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // If we are not editing, connect! 255310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (!mDialog.isEditing()) { 256413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh try { 257413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh connect(profile); 258413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh } catch (Exception e) { 259413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh Log.e(TAG, "connect", e); 260413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh } 261310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 262310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 263310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 264310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 265310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 266310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) { 267310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 268310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Log.v(TAG, "onCreateContextMenu() is called when mDialog != null"); 269310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return; 270310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 271310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 272310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (info instanceof AdapterContextMenuInfo) { 273310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Preference preference = (Preference) getListView().getItemAtPosition( 274310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh ((AdapterContextMenuInfo) info).position); 275310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference instanceof VpnPreference) { 276310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile profile = ((VpnPreference) preference).getProfile(); 277310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mSelectedKey = profile.key; 278310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh menu.setHeaderTitle(profile.name); 279310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh menu.add(Menu.NONE, R.string.vpn_menu_edit, 0, R.string.vpn_menu_edit); 280310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh menu.add(Menu.NONE, R.string.vpn_menu_delete, 0, R.string.vpn_menu_delete); 281310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 282310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 283310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 284310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 285310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 286310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public boolean onContextItemSelected(MenuItem item) { 287310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 288310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Log.v(TAG, "onContextItemSelected() is called when mDialog != null"); 289310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return false; 290310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 291310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 292310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnPreference preference = mPreferences.get(mSelectedKey); 293310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference == null) { 294310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Log.v(TAG, "onContextItemSelected() is called but no preference is found"); 295310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return false; 296310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 297310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 298310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh switch (item.getItemId()) { 299310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh case R.string.vpn_menu_edit: 300310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog = new VpnDialog(getActivity(), this, preference.getProfile(), true); 301310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.setOnDismissListener(this); 302310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.show(); 303310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 304310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh case R.string.vpn_menu_delete: 305310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh disconnect(mSelectedKey); 306310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh getPreferenceScreen().removePreference(preference); 307310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mPreferences.remove(mSelectedKey); 308310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mKeyStore.delete(Credentials.VPN + mSelectedKey); 309310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 310310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 311310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return false; 312310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 313310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 314310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 315310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public boolean onPreferenceClick(Preference preference) { 316310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 317310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Log.v(TAG, "onPreferenceClick() is called when mDialog != null"); 318310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 319310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 320310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 321310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference instanceof VpnPreference) { 32297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh VpnProfile profile = ((VpnPreference) preference).getProfile(); 32397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (mInfo != null && profile.key.equals(mInfo.key) && 32497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mInfo.state == LegacyVpnInfo.STATE_CONNECTED) { 32597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh try { 32697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mInfo.intent.send(); 32797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh return true; 32897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } catch (Exception e) { 32997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh // ignore 33097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 33197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 33297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mDialog = new VpnDialog(getActivity(), this, profile, false); 333310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } else { 334310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Generate a new key. Here we just use the current time. 335310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh long millis = System.currentTimeMillis(); 336310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh while (mPreferences.containsKey(Long.toHexString(millis))) { 337310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh ++millis; 338310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 339310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog = new VpnDialog(getActivity(), this, 340310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh new VpnProfile(Long.toHexString(millis)), true); 341310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 342310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.setOnDismissListener(this); 343310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.show(); 344310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 345310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 346310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 347310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 348310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public boolean handleMessage(Message message) { 349bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh mUpdater.removeMessages(0); 350310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 351310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (isResumed()) { 35297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh try { 35397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh LegacyVpnInfo info = mService.getLegacyVpnInfo(); 35497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (mInfo != null) { 35597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh VpnPreference preference = mPreferences.get(mInfo.key); 35697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (preference != null) { 35797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh preference.update(-1); 35897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 35997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mInfo = null; 36097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 36197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (info != null) { 36297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh VpnPreference preference = mPreferences.get(info.key); 36397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (preference != null) { 36497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh preference.update(info.state); 36597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mInfo = info; 36697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 36797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 36897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } catch (Exception e) { 36997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh // ignore 37097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 371bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh mUpdater.sendEmptyMessageDelayed(0, 1000); 372310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 373310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 374310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 375310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 376f35130dd79c100097025585c0b5a5ebbd38a414eChia-chi Yeh private void connect(VpnProfile profile) throws Exception { 377745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkey try { 378745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkey mService.startLegacyVpn(profile); 379745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkey } catch (IllegalStateException e) { 380745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkey Toast.makeText(getActivity(), R.string.vpn_no_network, Toast.LENGTH_LONG).show(); 381d95ec871138ebb367cfd8b67b4814438ac30c628Chia-chi Yeh } 382310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 383310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 384310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private void disconnect(String key) { 38597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (mInfo != null && key.equals(mInfo.key)) { 38697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh try { 38797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN); 38897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } catch (Exception e) { 38997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh // ignore 39097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 39197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 392310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 393310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 394b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani @Override 395b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani protected int getHelpResource() { 396b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani return R.string.help_url_vpn; 397b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani } 398b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani 3999fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private static class VpnPreference extends Preference { 400310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private VpnProfile mProfile; 40197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh private int mState = -1; 402310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 403310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnPreference(Context context, VpnProfile profile) { 404310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh super(context); 405310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh setPersistent(false); 40697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh setOrder(0); 407310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 408310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mProfile = profile; 409310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh update(); 410310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 411310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 412310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile getProfile() { 413310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return mProfile; 414310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 415310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 416310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh void update(VpnProfile profile) { 417310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mProfile = profile; 418310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh update(); 419310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 420310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 42197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh void update(int state) { 42297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mState = state; 42397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh update(); 42497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 42597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh 426310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh void update() { 42797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (mState < 0) { 428310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh String[] types = getContext().getResources() 429310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh .getStringArray(R.array.vpn_types_long); 430310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh setSummary(types[mProfile.type]); 43197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } else { 43297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh String[] states = getContext().getResources() 43397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh .getStringArray(R.array.vpn_states); 43497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh setSummary(states[mState]); 435310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 436310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh setTitle(mProfile.name); 43797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh notifyHierarchyChanged(); 438310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 439310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 440310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 441310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public int compareTo(Preference preference) { 442bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh int result = -1; 443310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference instanceof VpnPreference) { 444310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnPreference another = (VpnPreference) preference; 445310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if ((result = another.mState - mState) == 0 && 446310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh (result = mProfile.name.compareTo(another.mProfile.name)) == 0 && 447310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh (result = mProfile.type - another.mProfile.type) == 0) { 448310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh result = mProfile.key.compareTo(another.mProfile.key); 449310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 450310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 451310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return result; 452310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 453310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 4549fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4559fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey /** 4569fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey * Dialog to configure always-on VPN. 4579fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey */ 4589fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public static class LockdownConfigFragment extends DialogFragment { 4599fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private List<VpnProfile> mProfiles; 4609fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private List<CharSequence> mTitles; 4619fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private int mCurrentIndex; 4629fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4639fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private static class TitleAdapter extends ArrayAdapter<CharSequence> { 4649fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public TitleAdapter(Context context, List<CharSequence> objects) { 4659fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey super(context, com.android.internal.R.layout.select_dialog_singlechoice_holo, 4669fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey android.R.id.text1, objects); 4679fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4689fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4699fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4709fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public static void show(VpnSettings parent) { 4719fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (!parent.isAdded()) return; 4729fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4739fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final LockdownConfigFragment dialog = new LockdownConfigFragment(); 4749fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey dialog.show(parent.getFragmentManager(), TAG_LOCKDOWN); 4759fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4769fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4779fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private static String getStringOrNull(KeyStore keyStore, String key) { 4789fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final byte[] value = keyStore.get(Credentials.LOCKDOWN_VPN); 4799fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return value == null ? null : new String(value); 4809fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4819fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4829fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private void initProfiles(KeyStore keyStore, Resources res) { 4839fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final String lockdownKey = getStringOrNull(keyStore, Credentials.LOCKDOWN_VPN); 4849fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 485f5de1db28a61d159e62ef42f64a2cdcb316d0c2cJeff Sharkey mProfiles = loadVpnProfiles(keyStore, VpnProfile.TYPE_PPTP); 4869fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mTitles = Lists.newArrayList(); 4879fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mTitles.add(res.getText(R.string.vpn_lockdown_none)); 4889fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mCurrentIndex = 0; 4899fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4909fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey for (VpnProfile profile : mProfiles) { 4919fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (TextUtils.equals(profile.key, lockdownKey)) { 4929fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mCurrentIndex = mTitles.size(); 4939fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4949fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mTitles.add(profile.name); 4959fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4969fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4979fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4989fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey @Override 4999fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public Dialog onCreateDialog(Bundle savedInstanceState) { 5009fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final Context context = getActivity(); 5019fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final KeyStore keyStore = KeyStore.getInstance(); 5029fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5039fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey initProfiles(keyStore, context.getResources()); 5049fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5059fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final AlertDialog.Builder builder = new AlertDialog.Builder(context); 5069fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext()); 5079fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5089fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey builder.setTitle(R.string.vpn_menu_lockdown); 5099fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5109fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final View view = dialogInflater.inflate(R.layout.vpn_lockdown_editor, null, false); 5119fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final ListView listView = (ListView) view.findViewById(android.R.id.list); 5129fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 5139fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey listView.setAdapter(new TitleAdapter(context, mTitles)); 5149fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey listView.setItemChecked(mCurrentIndex, true); 5159fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey builder.setView(view); 5169fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5179fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 5189fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey @Override 5199fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public void onClick(DialogInterface dialog, int which) { 5209fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final int newIndex = listView.getCheckedItemPosition(); 5219fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (mCurrentIndex == newIndex) return; 5229fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5239fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (newIndex == 0) { 5249fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey keyStore.delete(Credentials.LOCKDOWN_VPN); 5259fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5269fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } else { 5279fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final VpnProfile profile = mProfiles.get(newIndex - 1); 5289fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (!profile.isValidLockdownProfile()) { 5299fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey Toast.makeText(context, R.string.vpn_lockdown_config_error, 5309fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey Toast.LENGTH_LONG).show(); 5319fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return; 5329fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5339fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey keyStore.put(Credentials.LOCKDOWN_VPN, profile.key.getBytes()); 5349fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5359fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5369fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey // kick profiles since we changed them 5379fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey ConnectivityManager.from(getActivity()).updateLockdownVpn(); 5389fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5399fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey }); 5409fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5419fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return builder.create(); 5429fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5439fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5449fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 545f5de1db28a61d159e62ef42f64a2cdcb316d0c2cJeff Sharkey private static List<VpnProfile> loadVpnProfiles(KeyStore keyStore, int... excludeTypes) { 5469fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final ArrayList<VpnProfile> result = Lists.newArrayList(); 5479fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final String[] keys = keyStore.saw(Credentials.VPN); 5489fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (keys != null) { 5499fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey for (String key : keys) { 5509fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final VpnProfile profile = VpnProfile.decode( 5519fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey key, keyStore.get(Credentials.VPN + key)); 552f5de1db28a61d159e62ef42f64a2cdcb316d0c2cJeff Sharkey if (profile != null && !ArrayUtils.contains(excludeTypes, profile.type)) { 5539fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey result.add(profile); 5549fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5559fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5569fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5579fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return result; 5589fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 559310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh} 560