Home | History | Annotate | Download | only in vpn
      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 
     17 package com.android.settings.vpn;
     18 
     19 import com.android.settings.R;
     20 
     21 import android.app.Dialog;
     22 import android.content.ComponentName;
     23 import android.content.Context;
     24 import android.content.ServiceConnection;
     25 import android.net.vpn.IVpnService;
     26 import android.net.vpn.VpnManager;
     27 import android.net.vpn.VpnProfile;
     28 import android.net.vpn.VpnState;
     29 import android.os.ConditionVariable;
     30 import android.os.IBinder;
     31 import android.os.RemoteException;
     32 import android.text.TextUtils;
     33 import android.util.Log;
     34 import android.view.View;
     35 import android.widget.CheckBox;
     36 import android.widget.TextView;
     37 
     38 import 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  */
     44 public 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