1/* 2 * Copyright (C) 2009 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.vpn; 18 19import com.android.settings.R; 20 21import android.app.Dialog; 22import android.content.ComponentName; 23import android.content.Context; 24import android.content.ServiceConnection; 25import android.net.vpn.IVpnService; 26import android.net.vpn.VpnManager; 27import android.net.vpn.VpnProfile; 28import android.net.vpn.VpnState; 29import android.os.ConditionVariable; 30import android.os.IBinder; 31import android.os.RemoteException; 32import android.text.TextUtils; 33import android.util.Log; 34import android.view.View; 35import android.widget.CheckBox; 36import android.widget.TextView; 37 38import java.io.IOException; 39 40/** 41 * A {@link VpnProfileActor} that provides an authentication view for users to 42 * input username and password before connecting to the VPN server. 43 */ 44public class AuthenticationActor implements VpnProfileActor { 45 private static final String TAG = AuthenticationActor.class.getName(); 46 47 private Context mContext; 48 private VpnProfile mProfile; 49 private VpnManager mVpnManager; 50 51 public AuthenticationActor(Context context, VpnProfile p) { 52 mContext = context; 53 mProfile = p; 54 mVpnManager = new VpnManager(context); 55 } 56 57 //@Override 58 public VpnProfile getProfile() { 59 return mProfile; 60 } 61 62 //@Override 63 public boolean isConnectDialogNeeded() { 64 return true; 65 } 66 67 //@Override 68 public String validateInputs(Dialog d) { 69 TextView usernameView = (TextView) d.findViewById(R.id.username_value); 70 TextView passwordView = (TextView) d.findViewById(R.id.password_value); 71 Context c = mContext; 72 if (TextUtils.isEmpty(usernameView.getText().toString())) { 73 return c.getString(R.string.vpn_a_username); 74 } else if (TextUtils.isEmpty(passwordView.getText().toString())) { 75 return c.getString(R.string.vpn_a_password); 76 } else { 77 return null; 78 } 79 } 80 81 //@Override 82 public void connect(Dialog d) { 83 TextView usernameView = (TextView) d.findViewById(R.id.username_value); 84 TextView passwordView = (TextView) d.findViewById(R.id.password_value); 85 CheckBox saveUsername = (CheckBox) d.findViewById(R.id.save_username); 86 87 try { 88 setSavedUsername(saveUsername.isChecked() 89 ? usernameView.getText().toString() 90 : ""); 91 } catch (IOException e) { 92 Log.e(TAG, "setSavedUsername()", e); 93 } 94 95 connect(usernameView.getText().toString(), 96 passwordView.getText().toString()); 97 passwordView.setText(""); 98 } 99 100 //@Override 101 public View createConnectView() { 102 View v = View.inflate(mContext, R.layout.vpn_connect_dialog_view, null); 103 TextView usernameView = (TextView) v.findViewById(R.id.username_value); 104 TextView passwordView = (TextView) v.findViewById(R.id.password_value); 105 CheckBox saveUsername = (CheckBox) v.findViewById(R.id.save_username); 106 107 String username = mProfile.getSavedUsername(); 108 if (!TextUtils.isEmpty(username)) { 109 usernameView.setText(username); 110 saveUsername.setChecked(true); 111 passwordView.requestFocus(); 112 } 113 return v; 114 } 115 116 protected Context getContext() { 117 return mContext; 118 } 119 120 private void connect(final String username, final String password) { 121 mVpnManager.startVpnService(); 122 ServiceConnection c = new ServiceConnection() { 123 public void onServiceConnected(ComponentName className, 124 IBinder service) { 125 try { 126 boolean success = IVpnService.Stub.asInterface(service) 127 .connect(mProfile, username, password); 128 if (!success) { 129 Log.d(TAG, "~~~~~~ connect() failed!"); 130 } else { 131 Log.d(TAG, "~~~~~~ connect() succeeded!"); 132 } 133 } catch (Throwable e) { 134 Log.e(TAG, "connect()", e); 135 broadcastConnectivity(VpnState.IDLE, 136 VpnManager.VPN_ERROR_CONNECTION_FAILED); 137 } finally { 138 mContext.unbindService(this); 139 } 140 } 141 142 public void onServiceDisconnected(ComponentName className) { 143 checkStatus(); 144 } 145 }; 146 if (!bindService(c)) { 147 broadcastConnectivity(VpnState.IDLE, 148 VpnManager.VPN_ERROR_CONNECTION_FAILED); 149 } 150 } 151 152 //@Override 153 public void disconnect() { 154 ServiceConnection c = new ServiceConnection() { 155 public void onServiceConnected(ComponentName className, 156 IBinder service) { 157 try { 158 IVpnService.Stub.asInterface(service).disconnect(); 159 } catch (RemoteException e) { 160 Log.e(TAG, "disconnect()", e); 161 checkStatus(); 162 } finally { 163 mContext.unbindService(this); 164 } 165 } 166 167 public void onServiceDisconnected(ComponentName className) { 168 checkStatus(); 169 } 170 }; 171 if (!bindService(c)) { 172 checkStatus(); 173 } 174 } 175 176 //@Override 177 public void checkStatus() { 178 final ConditionVariable cv = new ConditionVariable(); 179 cv.close(); 180 ServiceConnection c = new ServiceConnection() { 181 public synchronized void onServiceConnected(ComponentName className, 182 IBinder service) { 183 cv.open(); 184 try { 185 IVpnService.Stub.asInterface(service).checkStatus(mProfile); 186 } catch (RemoteException e) { 187 Log.e(TAG, "checkStatus()", e); 188 broadcastConnectivity(VpnState.IDLE); 189 } finally { 190 mContext.unbindService(this); 191 } 192 } 193 194 public void onServiceDisconnected(ComponentName className) { 195 cv.open(); 196 broadcastConnectivity(VpnState.IDLE); 197 mContext.unbindService(this); 198 } 199 }; 200 if (bindService(c)) { 201 // wait for a second, let status propagate 202 if (!cv.block(1000)) broadcastConnectivity(VpnState.IDLE); 203 } 204 } 205 206 private boolean bindService(ServiceConnection c) { 207 return mVpnManager.bindVpnService(c); 208 } 209 210 private void broadcastConnectivity(VpnState s) { 211 mVpnManager.broadcastConnectivity(mProfile.getName(), s); 212 } 213 214 private void broadcastConnectivity(VpnState s, int errorCode) { 215 mVpnManager.broadcastConnectivity(mProfile.getName(), s, errorCode); 216 } 217 218 private void setSavedUsername(String name) throws IOException { 219 if (!name.equals(mProfile.getSavedUsername())) { 220 mProfile.setSavedUsername(name); 221 VpnSettings.saveProfileToStorage(mProfile); 222 } 223 } 224} 225