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 699fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey // TODO: migrate to using DialogFragment when editing 709fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 7197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh private final IConnectivityManager mService = IConnectivityManager.Stub 7297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh .asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); 73310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private final KeyStore mKeyStore = KeyStore.getInstance(); 74310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private boolean mUnlocking = false; 75310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 7688b0140241c646c87d356748621cef28a3105466Robert Greenwalt private HashMap<String, VpnPreference> mPreferences = new HashMap<String, VpnPreference>(); 77310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private VpnDialog mDialog; 78bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh 79bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh private Handler mUpdater; 8097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh private LegacyVpnInfo mInfo; 81bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh 82bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh // The key of the profile for the current ContextMenu. 83310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private String mSelectedKey; 84310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 85310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 86310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onCreate(Bundle savedState) { 87310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh super.onCreate(savedState); 889fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 899fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey setHasOptionsMenu(true); 90310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh addPreferencesFromResource(R.xml.vpn_settings2); 91310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 92310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (savedState != null) { 93310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile profile = VpnProfile.decode(savedState.getString("VpnKey"), 94310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.getByteArray("VpnProfile")); 95310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (profile != null) { 96310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog = new VpnDialog(getActivity(), this, profile, 97310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.getBoolean("VpnEditing")); 98310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 99310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 100310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 101310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 102310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 1039fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 1049fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey super.onCreateOptionsMenu(menu, inflater); 1059fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey inflater.inflate(R.menu.vpn, menu); 1069fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1079fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 1089fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey @Override 10907d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey public void onPrepareOptionsMenu(Menu menu) { 11007d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey super.onPrepareOptionsMenu(menu); 11107d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey 11207d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey // Hide lockdown VPN on devices that require IMS authentication 11307d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey if (SystemProperties.getBoolean("persist.radio.imsregrequired", false)) { 11407d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey menu.findItem(R.id.vpn_lockdown).setVisible(false); 11507d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey } 11607d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey } 11707d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey 11807d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey @Override 1199fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public boolean onOptionsItemSelected(MenuItem item) { 1209fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey switch (item.getItemId()) { 1219fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey case R.id.vpn_create: { 1229fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey // Generate a new key. Here we just use the current time. 1239fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey long millis = System.currentTimeMillis(); 1249fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey while (mPreferences.containsKey(Long.toHexString(millis))) { 1259fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey ++millis; 1269fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1279fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mDialog = new VpnDialog( 1289fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey getActivity(), this, new VpnProfile(Long.toHexString(millis)), true); 1299fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mDialog.setOnDismissListener(this); 1309fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mDialog.show(); 1319fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return true; 1329fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1339fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey case R.id.vpn_lockdown: { 1349fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey LockdownConfigFragment.show(this); 1359fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return true; 1369fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1379fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1389fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return super.onOptionsItemSelected(item); 1399fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1409fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 1419fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey @Override 142310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onSaveInstanceState(Bundle savedState) { 143310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // We do not save view hierarchy, as they are just profiles. 144310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 145310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile profile = mDialog.getProfile(); 146310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.putString("VpnKey", profile.key); 147310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.putByteArray("VpnProfile", profile.encode()); 148310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.putBoolean("VpnEditing", mDialog.isEditing()); 149310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 150310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // else? 151310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 152310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 153310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 154310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onResume() { 155310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh super.onResume(); 156310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 157310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Check KeyStore here, so others do not need to deal with it. 158310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mKeyStore.state() != KeyStore.State.UNLOCKED) { 159310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (!mUnlocking) { 160310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Let us unlock KeyStore. See you later! 161310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Credentials.getInstance().unlock(getActivity()); 162310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } else { 163310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // We already tried, but it is still not working! 164d68dbe29bb0a6639bfd95449eb28e7d4b174a3feChia-chi Yeh finishFragment(); 165310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 166310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mUnlocking = !mUnlocking; 167310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return; 168310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 169310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 170310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Now KeyStore is always unlocked. Reset the flag. 171310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mUnlocking = false; 172310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 173310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Currently we are the only user of profiles in KeyStore. 174310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Assuming KeyStore and KeyGuard do the right thing, we can 175310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // safely cache profiles in the memory. 17688b0140241c646c87d356748621cef28a3105466Robert Greenwalt if (mPreferences.size() == 0) { 177d501b5c963c0cbcc9c666f502229599464eaf3fdChia-chi Yeh PreferenceGroup group = getPreferenceScreen(); 178310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 1799fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final Context context = getActivity(); 1809fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final List<VpnProfile> profiles = loadVpnProfiles(mKeyStore); 1819fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey for (VpnProfile profile : profiles) { 1829fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final VpnPreference pref = new VpnPreference(context, profile); 1839fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey pref.setOnPreferenceClickListener(this); 1849fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mPreferences.put(profile.key, pref); 1859fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey group.addPreference(pref); 186310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 187310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 188310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 189310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Show the dialog if there is one. 190310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 191310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.setOnDismissListener(this); 192310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.show(); 193310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 194310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 195310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Start monitoring. 196bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh if (mUpdater == null) { 197bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh mUpdater = new Handler(this); 198310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 199bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh mUpdater.sendEmptyMessage(0); 200310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 201310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Register for context menu. Hmmm, getListView() is hidden? 202310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh registerForContextMenu(getListView()); 203310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 204310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 205310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 206310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onPause() { 207310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh super.onPause(); 208310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 209310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Hide the dialog if there is one. 210310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 211310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.setOnDismissListener(null); 212310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.dismiss(); 213310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 214310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 215310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Unregister for context menu. 2166d4334be691815cd9615b0fdebb756999a9c06a3Chia-chi Yeh if (getView() != null) { 2176d4334be691815cd9615b0fdebb756999a9c06a3Chia-chi Yeh unregisterForContextMenu(getListView()); 2186d4334be691815cd9615b0fdebb756999a9c06a3Chia-chi Yeh } 219310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 220310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 221310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 222310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onDismiss(DialogInterface dialog) { 223310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Here is the exit of a dialog. 224310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog = null; 225310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 226310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 227310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 228310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onClick(DialogInterface dialog, int button) { 229310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (button == DialogInterface.BUTTON_POSITIVE) { 230310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Always save the profile. 231310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile profile = mDialog.getProfile(); 232310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mKeyStore.put(Credentials.VPN + profile.key, profile.encode()); 233310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 234310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Update the preference. 235310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnPreference preference = mPreferences.get(profile.key); 236310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference != null) { 237310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh disconnect(profile.key); 238310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh preference.update(profile); 239310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } else { 240310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh preference = new VpnPreference(getActivity(), profile); 2419fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey preference.setOnPreferenceClickListener(this); 242310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mPreferences.put(profile.key, preference); 243310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh getPreferenceScreen().addPreference(preference); 244310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 245310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 246310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // If we are not editing, connect! 247310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (!mDialog.isEditing()) { 248413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh try { 249413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh connect(profile); 250413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh } catch (Exception e) { 251413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh Log.e(TAG, "connect", e); 252413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh } 253310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 254310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 255310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 256310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 257310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 258310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) { 259310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 260310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Log.v(TAG, "onCreateContextMenu() is called when mDialog != null"); 261310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return; 262310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 263310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 264310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (info instanceof AdapterContextMenuInfo) { 265310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Preference preference = (Preference) getListView().getItemAtPosition( 266310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh ((AdapterContextMenuInfo) info).position); 267310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference instanceof VpnPreference) { 268310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile profile = ((VpnPreference) preference).getProfile(); 269310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mSelectedKey = profile.key; 270310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh menu.setHeaderTitle(profile.name); 271310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh menu.add(Menu.NONE, R.string.vpn_menu_edit, 0, R.string.vpn_menu_edit); 272310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh menu.add(Menu.NONE, R.string.vpn_menu_delete, 0, R.string.vpn_menu_delete); 273310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 274310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 275310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 276310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 277310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 278310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public boolean onContextItemSelected(MenuItem item) { 279310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 280310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Log.v(TAG, "onContextItemSelected() is called when mDialog != null"); 281310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return false; 282310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 283310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 284310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnPreference preference = mPreferences.get(mSelectedKey); 285310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference == null) { 286310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Log.v(TAG, "onContextItemSelected() is called but no preference is found"); 287310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return false; 288310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 289310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 290310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh switch (item.getItemId()) { 291310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh case R.string.vpn_menu_edit: 292310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog = new VpnDialog(getActivity(), this, preference.getProfile(), true); 293310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.setOnDismissListener(this); 294310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.show(); 295310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 296310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh case R.string.vpn_menu_delete: 297310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh disconnect(mSelectedKey); 298310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh getPreferenceScreen().removePreference(preference); 299310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mPreferences.remove(mSelectedKey); 300310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mKeyStore.delete(Credentials.VPN + mSelectedKey); 301310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 302310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 303310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return false; 304310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 305310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 306310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 307310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public boolean onPreferenceClick(Preference preference) { 308310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 309310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Log.v(TAG, "onPreferenceClick() is called when mDialog != null"); 310310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 311310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 312310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 313310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference instanceof VpnPreference) { 31497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh VpnProfile profile = ((VpnPreference) preference).getProfile(); 31597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (mInfo != null && profile.key.equals(mInfo.key) && 31697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mInfo.state == LegacyVpnInfo.STATE_CONNECTED) { 31797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh try { 31897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mInfo.intent.send(); 31997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh return true; 32097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } catch (Exception e) { 32197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh // ignore 32297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 32397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 32497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mDialog = new VpnDialog(getActivity(), this, profile, false); 325310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } else { 326310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Generate a new key. Here we just use the current time. 327310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh long millis = System.currentTimeMillis(); 328310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh while (mPreferences.containsKey(Long.toHexString(millis))) { 329310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh ++millis; 330310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 331310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog = new VpnDialog(getActivity(), this, 332310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh new VpnProfile(Long.toHexString(millis)), true); 333310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 334310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.setOnDismissListener(this); 335310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.show(); 336310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 337310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 338310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 339310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 340310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public boolean handleMessage(Message message) { 341bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh mUpdater.removeMessages(0); 342310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 343310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (isResumed()) { 34497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh try { 34597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh LegacyVpnInfo info = mService.getLegacyVpnInfo(); 34697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (mInfo != null) { 34797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh VpnPreference preference = mPreferences.get(mInfo.key); 34897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (preference != null) { 34997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh preference.update(-1); 35097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 35197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mInfo = null; 35297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 35397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (info != null) { 35497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh VpnPreference preference = mPreferences.get(info.key); 35597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (preference != null) { 35697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh preference.update(info.state); 35797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mInfo = info; 35897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 35997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 36097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } catch (Exception e) { 36197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh // ignore 36297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 363bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh mUpdater.sendEmptyMessageDelayed(0, 1000); 364310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 365310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 366310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 367310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 368f35130dd79c100097025585c0b5a5ebbd38a414eChia-chi Yeh private void connect(VpnProfile profile) throws Exception { 369745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkey try { 370745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkey mService.startLegacyVpn(profile); 371745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkey } catch (IllegalStateException e) { 372745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkey Toast.makeText(getActivity(), R.string.vpn_no_network, Toast.LENGTH_LONG).show(); 373d95ec871138ebb367cfd8b67b4814438ac30c628Chia-chi Yeh } 374310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 375310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 376310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private void disconnect(String key) { 37797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (mInfo != null && key.equals(mInfo.key)) { 37897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh try { 37997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN); 38097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } catch (Exception e) { 38197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh // ignore 38297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 38397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 384310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 385310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 386b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani @Override 387b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani protected int getHelpResource() { 388b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani return R.string.help_url_vpn; 389b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani } 390b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani 3919fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private static class VpnPreference extends Preference { 392310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private VpnProfile mProfile; 39397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh private int mState = -1; 394310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 395310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnPreference(Context context, VpnProfile profile) { 396310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh super(context); 397310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh setPersistent(false); 39897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh setOrder(0); 399310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 400310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mProfile = profile; 401310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh update(); 402310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 403310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 404310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile getProfile() { 405310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return mProfile; 406310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 407310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 408310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh void update(VpnProfile profile) { 409310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mProfile = profile; 410310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh update(); 411310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 412310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 41397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh void update(int state) { 41497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mState = state; 41597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh update(); 41697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 41797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh 418310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh void update() { 41997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (mState < 0) { 420310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh String[] types = getContext().getResources() 421310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh .getStringArray(R.array.vpn_types_long); 422310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh setSummary(types[mProfile.type]); 42397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } else { 42497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh String[] states = getContext().getResources() 42597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh .getStringArray(R.array.vpn_states); 42697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh setSummary(states[mState]); 427310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 428310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh setTitle(mProfile.name); 42997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh notifyHierarchyChanged(); 430310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 431310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 432310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 433310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public int compareTo(Preference preference) { 434bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh int result = -1; 435310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference instanceof VpnPreference) { 436310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnPreference another = (VpnPreference) preference; 437310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if ((result = another.mState - mState) == 0 && 438310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh (result = mProfile.name.compareTo(another.mProfile.name)) == 0 && 439310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh (result = mProfile.type - another.mProfile.type) == 0) { 440310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh result = mProfile.key.compareTo(another.mProfile.key); 441310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 442310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 443310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return result; 444310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 445310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 4469fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4479fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey /** 4489fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey * Dialog to configure always-on VPN. 4499fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey */ 4509fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public static class LockdownConfigFragment extends DialogFragment { 4519fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private List<VpnProfile> mProfiles; 4529fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private List<CharSequence> mTitles; 4539fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private int mCurrentIndex; 4549fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4559fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private static class TitleAdapter extends ArrayAdapter<CharSequence> { 4569fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public TitleAdapter(Context context, List<CharSequence> objects) { 4579fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey super(context, com.android.internal.R.layout.select_dialog_singlechoice_holo, 4589fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey android.R.id.text1, objects); 4599fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4609fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4619fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4629fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public static void show(VpnSettings parent) { 4639fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (!parent.isAdded()) return; 4649fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4659fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final LockdownConfigFragment dialog = new LockdownConfigFragment(); 4669fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey dialog.show(parent.getFragmentManager(), TAG_LOCKDOWN); 4679fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4689fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4699fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private static String getStringOrNull(KeyStore keyStore, String key) { 4709fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final byte[] value = keyStore.get(Credentials.LOCKDOWN_VPN); 4719fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return value == null ? null : new String(value); 4729fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4739fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4749fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private void initProfiles(KeyStore keyStore, Resources res) { 4759fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final String lockdownKey = getStringOrNull(keyStore, Credentials.LOCKDOWN_VPN); 4769fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 477f5de1db28a61d159e62ef42f64a2cdcb316d0c2cJeff Sharkey mProfiles = loadVpnProfiles(keyStore, VpnProfile.TYPE_PPTP); 4789fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mTitles = Lists.newArrayList(); 4799fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mTitles.add(res.getText(R.string.vpn_lockdown_none)); 4809fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mCurrentIndex = 0; 4819fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4829fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey for (VpnProfile profile : mProfiles) { 4839fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (TextUtils.equals(profile.key, lockdownKey)) { 4849fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mCurrentIndex = mTitles.size(); 4859fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4869fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mTitles.add(profile.name); 4879fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4889fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4899fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4909fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey @Override 4919fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public Dialog onCreateDialog(Bundle savedInstanceState) { 4929fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final Context context = getActivity(); 4939fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final KeyStore keyStore = KeyStore.getInstance(); 4949fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4959fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey initProfiles(keyStore, context.getResources()); 4969fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4979fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final AlertDialog.Builder builder = new AlertDialog.Builder(context); 4989fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext()); 4999fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5009fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey builder.setTitle(R.string.vpn_menu_lockdown); 5019fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5029fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final View view = dialogInflater.inflate(R.layout.vpn_lockdown_editor, null, false); 5039fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final ListView listView = (ListView) view.findViewById(android.R.id.list); 5049fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 5059fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey listView.setAdapter(new TitleAdapter(context, mTitles)); 5069fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey listView.setItemChecked(mCurrentIndex, true); 5079fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey builder.setView(view); 5089fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5099fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 5109fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey @Override 5119fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public void onClick(DialogInterface dialog, int which) { 5129fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final int newIndex = listView.getCheckedItemPosition(); 5139fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (mCurrentIndex == newIndex) return; 5149fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5159fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (newIndex == 0) { 5169fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey keyStore.delete(Credentials.LOCKDOWN_VPN); 5179fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5189fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } else { 5199fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final VpnProfile profile = mProfiles.get(newIndex - 1); 5209fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (!profile.isValidLockdownProfile()) { 5219fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey Toast.makeText(context, R.string.vpn_lockdown_config_error, 5229fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey Toast.LENGTH_LONG).show(); 5239fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return; 5249fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5259fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey keyStore.put(Credentials.LOCKDOWN_VPN, profile.key.getBytes()); 5269fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5279fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5289fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey // kick profiles since we changed them 5299fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey ConnectivityManager.from(getActivity()).updateLockdownVpn(); 5309fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5319fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey }); 5329fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5339fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return builder.create(); 5349fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5359fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5369fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 537f5de1db28a61d159e62ef42f64a2cdcb316d0c2cJeff Sharkey private static List<VpnProfile> loadVpnProfiles(KeyStore keyStore, int... excludeTypes) { 5389fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final ArrayList<VpnProfile> result = Lists.newArrayList(); 5399fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final String[] keys = keyStore.saw(Credentials.VPN); 5409fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (keys != null) { 5419fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey for (String key : keys) { 5429fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final VpnProfile profile = VpnProfile.decode( 5439fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey key, keyStore.get(Credentials.VPN + key)); 544f5de1db28a61d159e62ef42f64a2cdcb316d0c2cJeff Sharkey if (profile != null && !ArrayUtils.contains(excludeTypes, profile.type)) { 5459fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey result.add(profile); 5469fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5479fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5489fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5499fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return result; 5509fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 551310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh} 552