Show an error dialog when errors occur while establishing the VPN
[strongswan.git] / src / frontends / android / src / org / strongswan / android / ui / VpnStateFragment.java
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 package org.strongswan.android.ui;
19
20 import org.strongswan.android.R;
21 import org.strongswan.android.data.VpnProfile;
22 import org.strongswan.android.logic.VpnStateService;
23 import org.strongswan.android.logic.VpnStateService.ErrorState;
24 import org.strongswan.android.logic.VpnStateService.State;
25 import org.strongswan.android.logic.VpnStateService.VpnStateListener;
26
27 import android.app.AlertDialog;
28 import android.app.Fragment;
29 import android.app.ProgressDialog;
30 import android.app.Service;
31 import android.content.ComponentName;
32 import android.content.Context;
33 import android.content.DialogInterface;
34 import android.content.Intent;
35 import android.content.ServiceConnection;
36 import android.graphics.Color;
37 import android.os.Bundle;
38 import android.os.IBinder;
39 import android.view.LayoutInflater;
40 import android.view.View;
41 import android.view.View.OnClickListener;
42 import android.view.ViewGroup;
43 import android.widget.Button;
44 import android.widget.TextView;
45
46 public class VpnStateFragment extends Fragment implements VpnStateListener
47 {
48 private TextView mProfileNameView;
49 private TextView mProfileView;
50 private TextView mStateView;
51 private int stateBaseColor;
52 private Button mActionButton;
53 private ProgressDialog mProgressDialog;
54 private State mState;
55 private AlertDialog mErrorDialog;
56 private VpnStateService mService;
57 private final ServiceConnection mServiceConnection = new ServiceConnection() {
58 @Override
59 public void onServiceDisconnected(ComponentName name)
60 {
61 mService = null;
62 }
63
64 @Override
65 public void onServiceConnected(ComponentName name, IBinder service)
66 {
67 mService = ((VpnStateService.LocalBinder)service).getService();
68 mService.registerListener(VpnStateFragment.this);
69 updateView();
70 }
71 };
72
73 @Override
74 public void onCreate(Bundle savedInstanceState)
75 {
76 super.onCreate(savedInstanceState);
77
78 /* bind to the service only seems to work from the ApplicationContext */
79 Context context = getActivity().getApplicationContext();
80 context.bindService(new Intent(context, VpnStateService.class),
81 mServiceConnection, Service.BIND_AUTO_CREATE);
82 }
83
84 @Override
85 public View onCreateView(LayoutInflater inflater, ViewGroup container,
86 Bundle savedInstanceState)
87 {
88 View view = inflater.inflate(R.layout.vpn_state_fragment, null);
89
90 mActionButton = (Button)view.findViewById(R.id.action);
91 mActionButton.setOnClickListener(new OnClickListener() {
92 @Override
93 public void onClick(View v)
94 {
95 if (mService != null)
96 {
97 mService.disconnect();
98 }
99 }
100 });
101 enableActionButton(false);
102
103 mStateView = (TextView)view.findViewById(R.id.vpn_state);
104 stateBaseColor = mStateView.getCurrentTextColor();
105 mProfileView = (TextView)view.findViewById(R.id.vpn_profile_label);
106 mProfileNameView = (TextView)view.findViewById(R.id.vpn_profile_name);
107
108 return view;
109 }
110
111 @Override
112 public void onStart()
113 {
114 super.onStart();
115 if (mService != null)
116 {
117 updateView();
118 }
119 }
120
121 @Override
122 public void onStop()
123 {
124 super.onStop();
125 hideErrorDialog();
126 hideProgressDialog();
127 }
128
129 @Override
130 public void onDestroy()
131 {
132 super.onDestroy();
133 if (mService != null)
134 {
135 mService.unregisterListener(this);
136 getActivity().getApplicationContext().unbindService(mServiceConnection);
137 }
138 }
139
140 @Override
141 public void stateChanged()
142 {
143 updateView();
144 }
145
146 public void updateView()
147 {
148 State state = mService.getState();
149 ErrorState error = ErrorState.NO_ERROR;
150 String name = "", gateway = "";
151
152 if (state != State.DISABLED)
153 {
154 VpnProfile profile = mService.getProfile();
155 if (profile != null)
156 {
157 name = profile.getName();
158 gateway = profile.getGateway();
159 }
160 error = mService.getErrorState();
161 }
162
163 if (reportError(name, state, error))
164 {
165 return;
166 }
167
168 if (state == mState)
169 { /* avoid unnecessary updates */
170 return;
171 }
172
173 hideProgressDialog();
174 enableActionButton(false);
175 mProfileNameView.setText(name);
176 mState = state;
177
178 switch (state)
179 {
180 case DISABLED:
181 showProfile(false);
182 mStateView.setText(R.string.state_disabled);
183 mStateView.setTextColor(stateBaseColor);
184 break;
185 case CONNECTING:
186 showProfile(true);
187 showConnectDialog(name, gateway);
188 mStateView.setText(R.string.state_connecting);
189 mStateView.setTextColor(stateBaseColor);
190 break;
191 case CONNECTED:
192 showProfile(true);
193 enableActionButton(true);
194 mStateView.setText(R.string.state_connected);
195 mStateView.setTextColor(Color.GREEN);
196 break;
197 case DISCONNECTING:
198 showProfile(true);
199 showDisconnectDialog(name);
200 mStateView.setText(R.string.state_disconnecting);
201 mStateView.setTextColor(stateBaseColor);
202 break;
203 }
204 }
205
206 private boolean reportError(String name, State state, ErrorState error)
207 {
208 if (error == ErrorState.NO_ERROR || state != State.CONNECTING && state != State.CONNECTED)
209 { /* we only report errors while initiating */
210 hideErrorDialog();
211 return false;
212 }
213 else if (mErrorDialog != null)
214 { /* we already show the dialog */
215 return true;
216 }
217 hideProgressDialog();
218 mProfileNameView.setText(name);
219 showProfile(true);
220 enableActionButton(false);
221 mStateView.setText(R.string.state_error);
222 mStateView.setTextColor(Color.RED);
223 switch (error)
224 {
225 case AUTH_FAILED:
226 showErrorDialog(R.string.error_auth_failed);
227 break;
228 case PEER_AUTH_FAILED:
229 showErrorDialog(R.string.error_peer_auth_failed);
230 break;
231 case LOOKUP_FAILED:
232 showErrorDialog(R.string.error_lookup_failed);
233 break;
234 case UNREACHABLE:
235 showErrorDialog(R.string.error_unreachable);
236 break;
237 default:
238 showErrorDialog(R.string.error_generic);
239 break;
240 }
241 return true;
242 }
243
244 private void showProfile(boolean show)
245 {
246 mProfileView.setVisibility(show ? View.VISIBLE : View.GONE);
247 mProfileNameView.setVisibility(show ? View.VISIBLE : View.GONE);
248 }
249
250 private void enableActionButton(boolean enable)
251 {
252 mActionButton.setEnabled(enable);
253 mActionButton.setVisibility(enable ? View.VISIBLE : View.GONE);
254 }
255
256 private void hideProgressDialog()
257 {
258 if (mProgressDialog != null)
259 {
260 mProgressDialog.dismiss();
261 mProgressDialog = null;
262 }
263 }
264
265 private void hideErrorDialog()
266 {
267 if (mErrorDialog != null)
268 {
269 mErrorDialog.dismiss();
270 mErrorDialog = null;
271 }
272 }
273
274 private void showConnectDialog(String profile, String gateway)
275 {
276 mProgressDialog = new ProgressDialog(getActivity());
277 mProgressDialog.setTitle(String.format(getString(R.string.connecting_title), profile));
278 mProgressDialog.setMessage(String.format(getString(R.string.connecting_message), gateway));
279 mProgressDialog.setIndeterminate(true);
280 mProgressDialog.setCancelable(false);
281 mProgressDialog.setButton(getString(android.R.string.cancel),
282 new DialogInterface.OnClickListener()
283 {
284 @Override
285 public void onClick(DialogInterface dialog, int which)
286 {
287 if (mService != null)
288 {
289 mService.disconnect();
290 }
291 }
292 });
293 mProgressDialog.show();
294 }
295
296 private void showDisconnectDialog(String profile)
297 {
298 mProgressDialog = new ProgressDialog(getActivity());
299 mProgressDialog.setMessage(getString(R.string.state_disconnecting));
300 mProgressDialog.setIndeterminate(true);
301 mProgressDialog.setCancelable(false);
302 mProgressDialog.show();
303 }
304
305 private void showErrorDialog(int textid)
306 {
307 mErrorDialog = new AlertDialog.Builder(getActivity())
308 .setMessage(getString(R.string.error_introduction) + " " + getString(textid))
309 .setCancelable(false)
310 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
311 @Override
312 public void onClick(DialogInterface dialog, int id)
313 {
314 mErrorDialog = null;
315 dialog.dismiss();
316 }
317 }).create();
318 mErrorDialog.show();
319 }
320 }