2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * Hochschule fuer Technik Rapperswil
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>.
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
18 package org
.strongswan
.android
.ui
;
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
;
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
.os
.Bundle
;
37 import android
.os
.IBinder
;
38 import android
.view
.LayoutInflater
;
39 import android
.view
.View
;
40 import android
.view
.View
.OnClickListener
;
41 import android
.view
.ViewGroup
;
42 import android
.widget
.Button
;
43 import android
.widget
.TextView
;
45 public class VpnStateFragment
extends Fragment
implements VpnStateListener
47 private static final String KEY_ERROR
= "error";
48 private static final String KEY_NAME
= "name";
50 private TextView mProfileNameView
;
51 private TextView mProfileView
;
52 private TextView mStateView
;
53 private int stateBaseColor
;
54 private Button mActionButton
;
55 private ProgressDialog mProgressDialog
;
57 private AlertDialog mErrorDialog
;
58 private ErrorState mError
;
59 private String mErrorProfileName
;
60 private VpnStateService mService
;
61 private final ServiceConnection mServiceConnection
= new ServiceConnection() {
63 public void onServiceDisconnected(ComponentName name
)
69 public void onServiceConnected(ComponentName name
, IBinder service
)
71 mService
= ((VpnStateService
.LocalBinder
)service
).getService();
72 mService
.registerListener(VpnStateFragment
.this);
78 public void onCreate(Bundle savedInstanceState
)
80 super.onCreate(savedInstanceState
);
82 /* bind to the service only seems to work from the ApplicationContext */
83 Context context
= getActivity().getApplicationContext();
84 context
.bindService(new Intent(context
, VpnStateService
.class),
85 mServiceConnection
, Service
.BIND_AUTO_CREATE
);
87 mError
= ErrorState
.NO_ERROR
;
88 if (savedInstanceState
!= null
&& savedInstanceState
.containsKey(KEY_ERROR
))
90 mError
= (ErrorState
)savedInstanceState
.getSerializable(KEY_ERROR
);
91 mErrorProfileName
= savedInstanceState
.getString(KEY_NAME
);
96 public void onSaveInstanceState(Bundle outState
)
98 super.onSaveInstanceState(outState
);
100 outState
.putSerializable(KEY_ERROR
, mError
);
101 outState
.putString(KEY_NAME
, mErrorProfileName
);
105 public View
onCreateView(LayoutInflater inflater
, ViewGroup container
,
106 Bundle savedInstanceState
)
108 View view
= inflater
.inflate(R
.layout
.vpn_state_fragment
, null
);
110 mActionButton
= (Button
)view
.findViewById(R
.id
.action
);
111 mActionButton
.setOnClickListener(new OnClickListener() {
113 public void onClick(View v
)
115 if (mService
!= null
)
117 mService
.disconnect();
121 enableActionButton(false
);
123 mStateView
= (TextView
)view
.findViewById(R
.id
.vpn_state
);
124 stateBaseColor
= mStateView
.getCurrentTextColor();
125 mProfileView
= (TextView
)view
.findViewById(R
.id
.vpn_profile_label
);
126 mProfileNameView
= (TextView
)view
.findViewById(R
.id
.vpn_profile_name
);
132 public void onStart()
135 if (mService
!= null
)
146 hideProgressDialog();
150 public void onDestroy()
153 if (mService
!= null
)
155 mService
.unregisterListener(this);
156 getActivity().getApplicationContext().unbindService(mServiceConnection
);
161 public void stateChanged()
166 public void updateView()
168 State state
= mService
.getState();
169 ErrorState error
= ErrorState
.NO_ERROR
;
170 String name
= "", gateway
= "";
172 if (state
!= State
.DISABLED
)
174 VpnProfile profile
= mService
.getProfile();
177 name
= profile
.getName();
178 gateway
= profile
.getGateway();
180 error
= mService
.getErrorState();
183 if (reportError(name
, state
, error
))
189 { /* avoid unnecessary updates */
193 hideProgressDialog();
194 enableActionButton(false
);
195 mProfileNameView
.setText(name
);
202 mStateView
.setText(R
.string
.state_disabled
);
203 mStateView
.setTextColor(stateBaseColor
);
207 showConnectDialog(name
, gateway
);
208 mStateView
.setText(R
.string
.state_connecting
);
209 mStateView
.setTextColor(stateBaseColor
);
213 enableActionButton(true
);
214 mStateView
.setText(R
.string
.state_connected
);
215 mStateView
.setTextColor(getResources().getColor(R
.color
.success_text
));
219 showDisconnectDialog(name
);
220 mStateView
.setText(R
.string
.state_disconnecting
);
221 mStateView
.setTextColor(stateBaseColor
);
226 private boolean reportError(String name
, State state
, ErrorState error
)
228 if (mError
!= ErrorState
.NO_ERROR
)
229 { /* we are currently reporting an error which was not yet dismissed */
231 name
= mErrorProfileName
;
233 else if (error
!= ErrorState
.NO_ERROR
&& (state
== State
.CONNECTING
|| state
== State
.CONNECTED
))
234 { /* while initiating we report errors */
236 mErrorProfileName
= name
;
239 { /* ignore all other errors */
240 error
= ErrorState
.NO_ERROR
;
242 if (error
== ErrorState
.NO_ERROR
)
247 else if (mErrorDialog
!= null
)
248 { /* we already show the dialog */
251 hideProgressDialog();
252 mProfileNameView
.setText(name
);
254 enableActionButton(false
);
255 mStateView
.setText(R
.string
.state_error
);
256 mStateView
.setTextColor(getResources().getColor(R
.color
.error_text
));
260 showErrorDialog(R
.string
.error_auth_failed
);
262 case PEER_AUTH_FAILED
:
263 showErrorDialog(R
.string
.error_peer_auth_failed
);
266 showErrorDialog(R
.string
.error_lookup_failed
);
269 showErrorDialog(R
.string
.error_unreachable
);
272 showErrorDialog(R
.string
.error_generic
);
278 private void showProfile(boolean show
)
280 mProfileView
.setVisibility(show ? View
.VISIBLE
: View
.GONE
);
281 mProfileNameView
.setVisibility(show ? View
.VISIBLE
: View
.GONE
);
284 private void enableActionButton(boolean enable
)
286 mActionButton
.setEnabled(enable
);
287 mActionButton
.setVisibility(enable ? View
.VISIBLE
: View
.GONE
);
290 private void hideProgressDialog()
292 if (mProgressDialog
!= null
)
294 mProgressDialog
.dismiss();
295 mProgressDialog
= null
;
299 private void hideErrorDialog()
301 if (mErrorDialog
!= null
)
303 mErrorDialog
.dismiss();
308 private void showConnectDialog(String profile
, String gateway
)
310 mProgressDialog
= new ProgressDialog(getActivity());
311 mProgressDialog
.setTitle(String
.format(getString(R
.string
.connecting_title
), profile
));
312 mProgressDialog
.setMessage(String
.format(getString(R
.string
.connecting_message
), gateway
));
313 mProgressDialog
.setIndeterminate(true
);
314 mProgressDialog
.setCancelable(false
);
315 mProgressDialog
.setButton(getString(android
.R
.string
.cancel
),
316 new DialogInterface
.OnClickListener()
319 public void onClick(DialogInterface dialog
, int which
)
321 if (mService
!= null
)
323 mService
.disconnect();
327 mProgressDialog
.show();
330 private void showDisconnectDialog(String profile
)
332 mProgressDialog
= new ProgressDialog(getActivity());
333 mProgressDialog
.setMessage(getString(R
.string
.state_disconnecting
));
334 mProgressDialog
.setIndeterminate(true
);
335 mProgressDialog
.setCancelable(false
);
336 mProgressDialog
.show();
339 private void showErrorDialog(int textid
)
341 mErrorDialog
= new AlertDialog
.Builder(getActivity())
342 .setMessage(getString(R
.string
.error_introduction
) + " " + getString(textid
))
343 .setCancelable(false
)
344 .setPositiveButton(android
.R
.string
.ok
, new DialogInterface
.OnClickListener() {
346 public void onClick(DialogInterface dialog
, int id
)
347 { /* clear the error */
348 mError
= ErrorState
.NO_ERROR
;