OSDN Git Service

Add VPN settings classes to Settings app.
[android-x86/packages-apps-Settings.git] / src / com / android / settings / vpn / AuthenticationActor.java
1 /*
2  * Copyright (C) 2007 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.AlertDialog;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.ServiceConnection;
27 import android.net.vpn.IVpnService;
28 import android.net.vpn.VpnManager;
29 import android.net.vpn.VpnProfile;
30 import android.net.vpn.VpnState;
31 import android.os.Bundle;
32 import android.os.IBinder;
33 import android.os.Parcelable;
34 import android.os.RemoteException;
35 import android.util.Log;
36 import android.view.View;
37 import android.widget.EditText;
38 import android.widget.TextView;
39 import android.widget.Toast;
40
41 import java.io.IOException;
42
43 /**
44  */
45 public class AuthenticationActor implements VpnProfileActor,
46         DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
47     private static final String TAG = AuthenticationActor.class.getName();
48     private static final int ONE_SECOND = 1000; // ms
49
50     private static final String STATE_IS_DIALOG_OPEN = "is_dialog_open";
51     private static final String STATE_USERNAME = "username";
52     private static final String STATE_PASSWORD = "password";
53
54     private Context mContext;
55     private TextView mUsernameView;
56     private TextView mPasswordView;
57
58     private VpnProfile mProfile;
59     private View mView;
60     private VpnManager mVpnManager;
61     private AlertDialog mConnectDialog;
62     private AlertDialog mDisconnectDialog;
63
64     public AuthenticationActor(Context context, VpnProfile p) {
65         mContext = context;
66         mProfile = p;
67         mVpnManager = new VpnManager(context);
68     }
69
70     //@Override
71     public VpnProfile getProfile() {
72         return mProfile;
73     }
74
75     //@Override
76     public synchronized void connect() {
77         connect("", "");
78     }
79
80     //@Override
81     public void onClick(DialogInterface dialog, int which) {
82         dismissConnectDialog();
83         switch (which) {
84         case DialogInterface.BUTTON1: // connect
85             if (validateInputs()) {
86                 broadcastConnectivity(VpnState.CONNECTING);
87                 connectInternal();
88             }
89             break;
90
91         case DialogInterface.BUTTON2: // cancel
92             broadcastConnectivity(VpnState.CANCELLED);
93             break;
94         }
95     }
96
97     //@Override
98     public void onCancel(DialogInterface dialog) {
99         dismissConnectDialog();
100         broadcastConnectivity(VpnState.CANCELLED);
101     }
102
103     private void connect(String username, String password) {
104         Context c = mContext;
105         mConnectDialog = new AlertDialog.Builder(c)
106                 .setView(createConnectView(username, password))
107                 .setTitle(c.getString(R.string.vpn_connect_to) + " "
108                         + mProfile.getName())
109                 .setPositiveButton(c.getString(R.string.vpn_connect_button),
110                         this)
111                 .setNegativeButton(c.getString(R.string.vpn_cancel_button),
112                         this)
113                 .setOnCancelListener(this)
114                 .create();
115         mConnectDialog.show();
116     }
117
118     //@Override
119     public synchronized void onSaveState(Bundle outState) {
120         outState.putBoolean(STATE_IS_DIALOG_OPEN, (mConnectDialog != null));
121         if (mConnectDialog != null) {
122             assert(mConnectDialog.isShowing());
123             outState.putBoolean(STATE_IS_DIALOG_OPEN, (mConnectDialog != null));
124             outState.putString(STATE_USERNAME,
125                     mUsernameView.getText().toString());
126             outState.putString(STATE_PASSWORD,
127                     mPasswordView.getText().toString());
128             dismissConnectDialog();
129         }
130     }
131
132     //@Override
133     public synchronized void onRestoreState(final Bundle savedState) {
134         boolean isDialogOpen = savedState.getBoolean(STATE_IS_DIALOG_OPEN);
135         if (isDialogOpen) {
136             connect(savedState.getString(STATE_USERNAME),
137                     savedState.getString(STATE_PASSWORD));
138         }
139     }
140
141     private synchronized void dismissConnectDialog() {
142         mConnectDialog.dismiss();
143         mConnectDialog = null;
144     }
145
146     private void connectInternal() {
147         mVpnManager.startVpnService();
148         ServiceConnection c = new ServiceConnection() {
149             public void onServiceConnected(ComponentName className,
150                     IBinder service) {
151                 boolean success = false;
152                 try {
153                     success = IVpnService.Stub.asInterface(service)
154                             .connect(mProfile,
155                                     mUsernameView.getText().toString(),
156                                     mPasswordView.getText().toString());
157                     mPasswordView.setText("");
158                 } catch (Throwable e) {
159                     Log.e(TAG, "connect()", e);
160                     checkStatus();
161                 } finally {
162                     mContext.unbindService(this);
163
164                     if (!success) {
165                         Log.d(TAG, "~~~~~~ connect() failed!");
166                         // TODO: pop up a dialog
167                         broadcastConnectivity(VpnState.IDLE);
168                     } else {
169                         Log.d(TAG, "~~~~~~ connect() succeeded!");
170                     }
171                 }
172             }
173
174             public void onServiceDisconnected(ComponentName className) {
175                 checkStatus();
176             }
177         };
178         if (!bindService(c)) broadcastConnectivity(VpnState.IDLE);
179     }
180
181     //@Override
182     public void disconnect() {
183         ServiceConnection c = new ServiceConnection() {
184             public void onServiceConnected(ComponentName className,
185                     IBinder service) {
186                 try {
187                     IVpnService.Stub.asInterface(service).disconnect();
188                 } catch (RemoteException e) {
189                     Log.e(TAG, "disconnect()", e);
190                     checkStatus();
191                 } finally {
192                     mContext.unbindService(this);
193                     broadcastConnectivity(VpnState.IDLE);
194                 }
195             }
196
197             public void onServiceDisconnected(ComponentName className) {
198                 checkStatus();
199             }
200         };
201         bindService(c);
202     }
203
204     //@Override
205     public void checkStatus() {
206         ServiceConnection c = new ServiceConnection() {
207             public synchronized void onServiceConnected(ComponentName className,
208                     IBinder service) {
209                 try {
210                     IVpnService.Stub.asInterface(service).checkStatus(mProfile);
211                 } catch (Throwable e) {
212                     Log.e(TAG, "checkStatus()", e);
213                 } finally {
214                     notify();
215                 }
216             }
217
218             public void onServiceDisconnected(ComponentName className) {
219                 // do nothing
220             }
221         };
222         if (bindService(c)) {
223             // wait for a second, let status propagate
224             wait(c, ONE_SECOND);
225         }
226         mContext.unbindService(c);
227     }
228
229     private boolean bindService(ServiceConnection c) {
230         return mVpnManager.bindVpnService(c);
231     }
232
233     private void broadcastConnectivity(VpnState s) {
234         mVpnManager.broadcastConnectivity(mProfile.getName(), s);
235     }
236
237     // returns true if inputs pass validation
238     private boolean validateInputs() {
239         Context c = mContext;
240         String error = null;
241         if (Util.isNullOrEmpty(mUsernameView.getText().toString())) {
242             error = c.getString(R.string.vpn_username);
243         } else if (Util.isNullOrEmpty(mPasswordView.getText().toString())) {
244             error = c.getString(R.string.vpn_password);
245         }
246         if (error == null) {
247             return true;
248         } else {
249             new AlertDialog.Builder(c)
250                     .setTitle(c.getString(R.string.vpn_you_miss_a_field))
251                     .setMessage(String.format(
252                             c.getString(R.string.vpn_please_fill_up), error))
253                     .setPositiveButton(c.getString(R.string.vpn_back_button),
254                             createBackButtonListener())
255                     .show();
256             return false;
257         }
258     }
259
260     private View createConnectView(String username, String password) {
261         View v = View.inflate(mContext, R.layout.vpn_connect_dialog_view, null);
262         mUsernameView = (TextView) v.findViewById(R.id.username_value);
263         mPasswordView = (TextView) v.findViewById(R.id.password_value);
264         mUsernameView.setText(username);
265         mPasswordView.setText(password);
266         copyFieldsFromOldView(v);
267         mView = v;
268         return v;
269     }
270
271     private void copyFieldsFromOldView(View newView) {
272         if (mView == null) return;
273         mUsernameView.setText(
274                 ((TextView) mView.findViewById(R.id.username_value)).getText());
275         mPasswordView.setText(
276                 ((TextView) mView.findViewById(R.id.password_value)).getText());
277     }
278
279     private DialogInterface.OnClickListener createBackButtonListener() {
280         return new DialogInterface.OnClickListener() {
281             public void onClick(DialogInterface dialog, int which) {
282                 dialog.dismiss();
283                 connect();
284             }
285         };
286     }
287
288     private void wait(Object o, int ms) {
289         synchronized (o) {
290             try {
291                 o.wait(ms);
292             } catch (Exception e) {}
293         }
294     }
295 }