blob: a6189a9f56d13c8539bfa1d13e163eafef1aebd9 [file] [log] [blame]
Robin Lee2bd92d52015-04-09 17:13:08 +01001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings.vpn2;
18
Lorenzo Colittic311c942015-10-13 15:23:38 +090019import java.util.Arrays;
20
Robin Lee2bd92d52015-04-09 17:13:08 +010021import android.app.Dialog;
22import android.app.DialogFragment;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.net.IConnectivityManager;
26import android.os.Bundle;
27import android.os.RemoteException;
28import android.os.ServiceManager;
Robin Lee01b35bc2015-05-12 18:35:37 +010029import android.os.UserHandle;
Robin Lee2bd92d52015-04-09 17:13:08 +010030import android.security.Credentials;
31import android.security.KeyStore;
32import android.util.Log;
33import android.widget.Toast;
34
35import com.android.internal.net.LegacyVpnInfo;
36import com.android.internal.net.VpnConfig;
37import com.android.internal.net.VpnProfile;
38import com.android.settings.R;
39
40/**
41 * Fragment wrapper around a {@link ConfigDialog}.
42 */
43public class ConfigDialogFragment extends DialogFragment implements
44 DialogInterface.OnClickListener {
45 private static final String TAG_CONFIG_DIALOG = "vpnconfigdialog";
46 private static final String TAG = "ConfigDialogFragment";
47
48 private static final String ARG_PROFILE = "profile";
49 private static final String ARG_EDITING = "editing";
50 private static final String ARG_EXISTS = "exists";
51
52 private final IConnectivityManager mService = IConnectivityManager.Stub.asInterface(
53 ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
54
55 private boolean mUnlocking = false;
56
57 public static void show(VpnSettings parent, VpnProfile profile, boolean edit, boolean exists) {
58 if (!parent.isAdded()) return;
59
60 Bundle args = new Bundle();
61 args.putParcelable(ARG_PROFILE, profile);
62 args.putBoolean(ARG_EDITING, edit);
63 args.putBoolean(ARG_EXISTS, exists);
64
65 final ConfigDialogFragment frag = new ConfigDialogFragment();
66 frag.setArguments(args);
67 frag.setTargetFragment(parent, 0);
68 frag.show(parent.getFragmentManager(), TAG_CONFIG_DIALOG);
69 }
70
71 @Override
72 public void onResume() {
73 super.onResume();
74
75 // Check KeyStore here, so others do not need to deal with it.
76 if (!KeyStore.getInstance().isUnlocked()) {
77 if (!mUnlocking) {
78 // Let us unlock KeyStore. See you later!
79 Credentials.getInstance().unlock(getActivity());
80 } else {
81 // We already tried, but it is still not working!
82 dismiss();
83 }
84 mUnlocking = !mUnlocking;
85 return;
86 }
87
88 // Now KeyStore is always unlocked. Reset the flag.
89 mUnlocking = false;
90 }
91
92 @Override
93 public Dialog onCreateDialog(Bundle savedInstanceState) {
94 Bundle args = getArguments();
95 VpnProfile profile = (VpnProfile) args.getParcelable(ARG_PROFILE);
96 boolean editing = args.getBoolean(ARG_EDITING);
97 boolean exists = args.getBoolean(ARG_EXISTS);
98
99 return new ConfigDialog(getActivity(), this, profile, editing, exists);
100 }
101
102 @Override
103 public void onClick(DialogInterface dialogInterface, int button) {
104 ConfigDialog dialog = (ConfigDialog) getDialog();
105 VpnProfile profile = dialog.getProfile();
106
107 if (button == DialogInterface.BUTTON_POSITIVE) {
108 // Update KeyStore entry
109 KeyStore.getInstance().put(Credentials.VPN + profile.key, profile.encode(),
110 KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
111
112 // Flush out old version of profile
113 disconnect(profile);
114
115 // If we are not editing, connect!
116 if (!dialog.isEditing()) {
117 try {
118 connect(profile);
119 } catch (RemoteException e) {
120 Log.e(TAG, "Failed to connect", e);
121 }
122 }
123 } else if (button == DialogInterface.BUTTON_NEUTRAL) {
124 // Disable profile if connected
125 disconnect(profile);
126
127 // Delete from KeyStore
Lorenzo Colittic311c942015-10-13 15:23:38 +0900128 KeyStore keyStore = KeyStore.getInstance();
129 keyStore.delete(Credentials.VPN + profile.key, KeyStore.UID_SELF);
130
131 // If this was the current lockdown VPN, clear it.
132 if (Arrays.equals(profile.key.getBytes(), keyStore.get(Credentials.LOCKDOWN_VPN))) {
133 keyStore.delete(Credentials.LOCKDOWN_VPN);
134 try {
135 mService.updateLockdownVpn();
136 } catch (RemoteException e) {
137 Log.e(TAG, "Failed to clear lockdown VPN configuration");
138 }
139 }
Robin Lee2bd92d52015-04-09 17:13:08 +0100140 }
141 dismiss();
142 }
143
144 @Override
Robin Lee2bd92d52015-04-09 17:13:08 +0100145 public void onCancel(DialogInterface dialog) {
146 dismiss();
147 super.onCancel(dialog);
148 }
149
150 private void connect(VpnProfile profile) throws RemoteException {
151 try {
152 mService.startLegacyVpn(profile);
153 } catch (IllegalStateException e) {
154 Toast.makeText(getActivity(), R.string.vpn_no_network, Toast.LENGTH_LONG).show();
155 }
156 }
157
158 private void disconnect(VpnProfile profile) {
159 try {
Robin Lee290784a2015-07-07 12:33:45 -0700160 LegacyVpnInfo connected = mService.getLegacyVpnInfo(UserHandle.myUserId());
Robin Lee2bd92d52015-04-09 17:13:08 +0100161 if (connected != null && profile.key.equals(connected.key)) {
Robin Lee01b35bc2015-05-12 18:35:37 +0100162 mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN,
163 UserHandle.myUserId());
Robin Lee2bd92d52015-04-09 17:13:08 +0100164 }
165 } catch (RemoteException e) {
166 Log.e(TAG, "Failed to disconnect", e);
167 }
168 }
169}