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 94310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (savedState != null) { 95310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile profile = VpnProfile.decode(savedState.getString("VpnKey"), 96310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.getByteArray("VpnProfile")); 97310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (profile != null) { 98310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog = new VpnDialog(getActivity(), this, profile, 99310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.getBoolean("VpnEditing")); 100310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 101310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 102310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 103310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 104310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 1059fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 1069fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey super.onCreateOptionsMenu(menu, inflater); 1079fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey inflater.inflate(R.menu.vpn, menu); 1089fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1099fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 1109fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey @Override 11107d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey public void onPrepareOptionsMenu(Menu menu) { 11207d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey super.onPrepareOptionsMenu(menu); 11307d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey 11407d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey // Hide lockdown VPN on devices that require IMS authentication 11507d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey if (SystemProperties.getBoolean("persist.radio.imsregrequired", false)) { 11607d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey menu.findItem(R.id.vpn_lockdown).setVisible(false); 11707d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey } 11807d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey } 11907d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey 12007d465ddb8629f128dde193d22de28cfd56663caJeff Sharkey @Override 1219fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public boolean onOptionsItemSelected(MenuItem item) { 1229fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey switch (item.getItemId()) { 1239fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey case R.id.vpn_create: { 1249fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey // Generate a new key. Here we just use the current time. 1259fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey long millis = System.currentTimeMillis(); 1269fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey while (mPreferences.containsKey(Long.toHexString(millis))) { 1279fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey ++millis; 1289fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1299fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mDialog = new VpnDialog( 1309fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey getActivity(), this, new VpnProfile(Long.toHexString(millis)), true); 1319fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mDialog.setOnDismissListener(this); 1329fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mDialog.show(); 1339fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return true; 1349fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1359fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey case R.id.vpn_lockdown: { 1369fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey LockdownConfigFragment.show(this); 1379fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return true; 1389fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1399fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1409fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return super.onOptionsItemSelected(item); 1419fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 1429fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 1439fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey @Override 144310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onSaveInstanceState(Bundle savedState) { 145310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // We do not save view hierarchy, as they are just profiles. 146310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 147310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile profile = mDialog.getProfile(); 148310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.putString("VpnKey", profile.key); 149310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.putByteArray("VpnProfile", profile.encode()); 150310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh savedState.putBoolean("VpnEditing", mDialog.isEditing()); 151310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 152310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // else? 153310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 154310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 155310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 156310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onResume() { 157310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh super.onResume(); 158310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 1591a55f95d45d2be39f3206cf1a4c3a1affd98cd92Jeff Sharkey final boolean pickLockdown = getActivity() 1601a55f95d45d2be39f3206cf1a4c3a1affd98cd92Jeff Sharkey .getIntent().getBooleanExtra(EXTRA_PICK_LOCKDOWN, false); 1611a55f95d45d2be39f3206cf1a4c3a1affd98cd92Jeff Sharkey if (pickLockdown) { 1621a55f95d45d2be39f3206cf1a4c3a1affd98cd92Jeff Sharkey LockdownConfigFragment.show(this); 1631a55f95d45d2be39f3206cf1a4c3a1affd98cd92Jeff Sharkey } 1641a55f95d45d2be39f3206cf1a4c3a1affd98cd92Jeff Sharkey 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(); 24014415168b170bd20ec158a2c40feb70a9f888c3cKenny Root mKeyStore.put(Credentials.VPN + profile.key, profile.encode(), KeyStore.UID_SELF, 24114415168b170bd20ec158a2c40feb70a9f888c3cKenny Root KeyStore.FLAG_ENCRYPTED); 242310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 243310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Update the preference. 244310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnPreference preference = mPreferences.get(profile.key); 245310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference != null) { 246310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh disconnect(profile.key); 247310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh preference.update(profile); 248310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } else { 249310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh preference = new VpnPreference(getActivity(), profile); 2509fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey preference.setOnPreferenceClickListener(this); 251310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mPreferences.put(profile.key, preference); 252310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh getPreferenceScreen().addPreference(preference); 253310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 254310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 255310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // If we are not editing, connect! 256310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (!mDialog.isEditing()) { 257413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh try { 258413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh connect(profile); 259413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh } catch (Exception e) { 260413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh Log.e(TAG, "connect", e); 261413b171159cec5ad1e7b3cf4f1f842b5f2debc05Chia-chi Yeh } 262310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 263310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 264310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 265310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 266310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 267310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) { 268310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 269310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Log.v(TAG, "onCreateContextMenu() is called when mDialog != null"); 270310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return; 271310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 272310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 273310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (info instanceof AdapterContextMenuInfo) { 274310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Preference preference = (Preference) getListView().getItemAtPosition( 275310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh ((AdapterContextMenuInfo) info).position); 276310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference instanceof VpnPreference) { 277310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile profile = ((VpnPreference) preference).getProfile(); 278310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mSelectedKey = profile.key; 279310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh menu.setHeaderTitle(profile.name); 280310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh menu.add(Menu.NONE, R.string.vpn_menu_edit, 0, R.string.vpn_menu_edit); 281310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh menu.add(Menu.NONE, R.string.vpn_menu_delete, 0, R.string.vpn_menu_delete); 282310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 283310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 284310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 285310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 286310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 287310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public boolean onContextItemSelected(MenuItem item) { 288310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 289310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Log.v(TAG, "onContextItemSelected() is called when mDialog != null"); 290310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return false; 291310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 292310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 293310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnPreference preference = mPreferences.get(mSelectedKey); 294310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference == null) { 295310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Log.v(TAG, "onContextItemSelected() is called but no preference is found"); 296310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return false; 297310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 298310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 299310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh switch (item.getItemId()) { 300310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh case R.string.vpn_menu_edit: 301310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog = new VpnDialog(getActivity(), this, preference.getProfile(), true); 302310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.setOnDismissListener(this); 303310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.show(); 304310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 305310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh case R.string.vpn_menu_delete: 306310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh disconnect(mSelectedKey); 307310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh getPreferenceScreen().removePreference(preference); 308310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mPreferences.remove(mSelectedKey); 309310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mKeyStore.delete(Credentials.VPN + mSelectedKey); 310310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 311310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 312310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return false; 313310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 314310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 315310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 316310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public boolean onPreferenceClick(Preference preference) { 317310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (mDialog != null) { 318310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh Log.v(TAG, "onPreferenceClick() is called when mDialog != null"); 319310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 320310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 321310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 322310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference instanceof VpnPreference) { 32397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh VpnProfile profile = ((VpnPreference) preference).getProfile(); 32497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (mInfo != null && profile.key.equals(mInfo.key) && 32597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mInfo.state == LegacyVpnInfo.STATE_CONNECTED) { 32697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh try { 32797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mInfo.intent.send(); 32897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh return true; 32997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } catch (Exception e) { 33097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh // ignore 33197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 33297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 33397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mDialog = new VpnDialog(getActivity(), this, profile, false); 334310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } else { 335310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh // Generate a new key. Here we just use the current time. 336310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh long millis = System.currentTimeMillis(); 337310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh while (mPreferences.containsKey(Long.toHexString(millis))) { 338310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh ++millis; 339310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 340310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog = new VpnDialog(getActivity(), this, 341310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh new VpnProfile(Long.toHexString(millis)), true); 342310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 343310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.setOnDismissListener(this); 344310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mDialog.show(); 345310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 346310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 347310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 348310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 349310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public boolean handleMessage(Message message) { 350bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh mUpdater.removeMessages(0); 351310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 352310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (isResumed()) { 35397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh try { 35497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh LegacyVpnInfo info = mService.getLegacyVpnInfo(); 35597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (mInfo != null) { 35697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh VpnPreference preference = mPreferences.get(mInfo.key); 35797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (preference != null) { 35897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh preference.update(-1); 35997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 36097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mInfo = null; 36197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 36297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (info != null) { 36397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh VpnPreference preference = mPreferences.get(info.key); 36497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (preference != null) { 36597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh preference.update(info.state); 36697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mInfo = info; 36797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 36897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 36997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } catch (Exception e) { 37097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh // ignore 37197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 372bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh mUpdater.sendEmptyMessageDelayed(0, 1000); 373310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 374310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return true; 375310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 376310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 377f35130dd79c100097025585c0b5a5ebbd38a414eChia-chi Yeh private void connect(VpnProfile profile) throws Exception { 378745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkey try { 379745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkey mService.startLegacyVpn(profile); 380745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkey } catch (IllegalStateException e) { 381745e6212e71f6fe9da863c9c9f7b092542929449Jeff Sharkey Toast.makeText(getActivity(), R.string.vpn_no_network, Toast.LENGTH_LONG).show(); 382d95ec871138ebb367cfd8b67b4814438ac30c628Chia-chi Yeh } 383310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 384310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 385310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private void disconnect(String key) { 38697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (mInfo != null && key.equals(mInfo.key)) { 38797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh try { 38897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN); 38997fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } catch (Exception e) { 39097fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh // ignore 39197fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 39297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 393310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 394310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 395b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani @Override 396b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani protected int getHelpResource() { 397b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani return R.string.help_url_vpn; 398b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani } 399b0b37ae21c172491bc170659b5f429601858ddc1Amith Yamasani 4009fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private static class VpnPreference extends Preference { 401310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh private VpnProfile mProfile; 40297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh private int mState = -1; 403310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 404310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnPreference(Context context, VpnProfile profile) { 405310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh super(context); 406310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh setPersistent(false); 40797fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh setOrder(0); 408310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 409310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mProfile = profile; 410310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh update(); 411310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 412310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 413310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnProfile getProfile() { 414310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return mProfile; 415310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 416310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 417310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh void update(VpnProfile profile) { 418310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh mProfile = profile; 419310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh update(); 420310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 421310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 42297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh void update(int state) { 42397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh mState = state; 42497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh update(); 42597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } 42697fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh 427310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh void update() { 42897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh if (mState < 0) { 429310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh String[] types = getContext().getResources() 430310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh .getStringArray(R.array.vpn_types_long); 431310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh setSummary(types[mProfile.type]); 43297fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh } else { 43397fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh String[] states = getContext().getResources() 43497fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh .getStringArray(R.array.vpn_states); 43597fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh setSummary(states[mState]); 436310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 437310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh setTitle(mProfile.name); 43897fd85fd9776f3fb5c35217e82bcbcb5aea8416dChia-chi Yeh notifyHierarchyChanged(); 439310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 440310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh 441310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh @Override 442310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh public int compareTo(Preference preference) { 443bbb5094be6673929bcb808cdeaf748a73be4dbf0Chia-chi Yeh int result = -1; 444310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if (preference instanceof VpnPreference) { 445310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh VpnPreference another = (VpnPreference) preference; 446310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh if ((result = another.mState - mState) == 0 && 447310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh (result = mProfile.name.compareTo(another.mProfile.name)) == 0 && 448310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh (result = mProfile.type - another.mProfile.type) == 0) { 449310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh result = mProfile.key.compareTo(another.mProfile.key); 450310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 451310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 452310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh return result; 453310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 454310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh } 4559fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4569fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey /** 4579fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey * Dialog to configure always-on VPN. 4589fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey */ 4599fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public static class LockdownConfigFragment extends DialogFragment { 4609fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private List<VpnProfile> mProfiles; 4619fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private List<CharSequence> mTitles; 4629fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private int mCurrentIndex; 4639fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4649fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private static class TitleAdapter extends ArrayAdapter<CharSequence> { 4659fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public TitleAdapter(Context context, List<CharSequence> objects) { 4669fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey super(context, com.android.internal.R.layout.select_dialog_singlechoice_holo, 4679fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey android.R.id.text1, objects); 4689fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4699fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4709fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4719fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public static void show(VpnSettings parent) { 4729fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (!parent.isAdded()) return; 4739fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4749fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final LockdownConfigFragment dialog = new LockdownConfigFragment(); 4759fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey dialog.show(parent.getFragmentManager(), TAG_LOCKDOWN); 4769fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4779fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4789fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private static String getStringOrNull(KeyStore keyStore, String key) { 4799fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final byte[] value = keyStore.get(Credentials.LOCKDOWN_VPN); 4809fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return value == null ? null : new String(value); 4819fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4829fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4839fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey private void initProfiles(KeyStore keyStore, Resources res) { 4849fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final String lockdownKey = getStringOrNull(keyStore, Credentials.LOCKDOWN_VPN); 4859fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 486f5de1db28a61d159e62ef42f64a2cdcb316d0c2cJeff Sharkey mProfiles = loadVpnProfiles(keyStore, VpnProfile.TYPE_PPTP); 4879fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mTitles = Lists.newArrayList(); 4889fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mTitles.add(res.getText(R.string.vpn_lockdown_none)); 4899fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mCurrentIndex = 0; 4909fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4919fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey for (VpnProfile profile : mProfiles) { 4929fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (TextUtils.equals(profile.key, lockdownKey)) { 4939fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mCurrentIndex = mTitles.size(); 4949fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4959fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey mTitles.add(profile.name); 4969fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4979fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 4989fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 4999fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey @Override 5009fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public Dialog onCreateDialog(Bundle savedInstanceState) { 5019fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final Context context = getActivity(); 5029fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final KeyStore keyStore = KeyStore.getInstance(); 5039fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5049fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey initProfiles(keyStore, context.getResources()); 5059fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5069fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final AlertDialog.Builder builder = new AlertDialog.Builder(context); 5079fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext()); 5089fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5099fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey builder.setTitle(R.string.vpn_menu_lockdown); 5109fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5119fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final View view = dialogInflater.inflate(R.layout.vpn_lockdown_editor, null, false); 5129fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final ListView listView = (ListView) view.findViewById(android.R.id.list); 5139fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 5149fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey listView.setAdapter(new TitleAdapter(context, mTitles)); 5159fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey listView.setItemChecked(mCurrentIndex, true); 5169fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey builder.setView(view); 5179fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5189fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 5199fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey @Override 5209fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey public void onClick(DialogInterface dialog, int which) { 5219fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final int newIndex = listView.getCheckedItemPosition(); 5229fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (mCurrentIndex == newIndex) return; 5239fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5249fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (newIndex == 0) { 5259fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey keyStore.delete(Credentials.LOCKDOWN_VPN); 5269fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5279fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } else { 5289fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final VpnProfile profile = mProfiles.get(newIndex - 1); 5299fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (!profile.isValidLockdownProfile()) { 5309fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey Toast.makeText(context, R.string.vpn_lockdown_config_error, 5319fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey Toast.LENGTH_LONG).show(); 5329fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return; 5339fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 53414415168b170bd20ec158a2c40feb70a9f888c3cKenny Root keyStore.put(Credentials.LOCKDOWN_VPN, profile.key.getBytes(), 53514415168b170bd20ec158a2c40feb70a9f888c3cKenny Root KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED); 5369fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5379fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5389fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey // kick profiles since we changed them 5399fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey ConnectivityManager.from(getActivity()).updateLockdownVpn(); 5409fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5419fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey }); 5429fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 5439fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return builder.create(); 5449fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5459fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5469fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey 547f5de1db28a61d159e62ef42f64a2cdcb316d0c2cJeff Sharkey private static List<VpnProfile> loadVpnProfiles(KeyStore keyStore, int... excludeTypes) { 5489fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final ArrayList<VpnProfile> result = Lists.newArrayList(); 5499fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final String[] keys = keyStore.saw(Credentials.VPN); 5509fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey if (keys != null) { 5519fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey for (String key : keys) { 5529fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey final VpnProfile profile = VpnProfile.decode( 5539fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey key, keyStore.get(Credentials.VPN + key)); 554f5de1db28a61d159e62ef42f64a2cdcb316d0c2cJeff Sharkey if (profile != null && !ArrayUtils.contains(excludeTypes, profile.type)) { 5559fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey result.add(profile); 5569fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5579fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5589fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 5599fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey return result; 5609fd7ac1ec7c0c3984f225a237bd6e3dbafc7f831Jeff Sharkey } 561310d619acba5cd1f7c8a55aa7906ed4f1c011bd8Chia-chi Yeh} 562