2 * Copyright (C) 2012-2018 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * HSR 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 android
.app
.Service
;
21 import android
.content
.ComponentName
;
22 import android
.content
.Context
;
23 import android
.content
.Intent
;
24 import android
.content
.ServiceConnection
;
25 import android
.os
.Bundle
;
26 import android
.os
.IBinder
;
27 import android
.support
.v4
.app
.Fragment
;
28 import android
.support
.v4
.content
.ContextCompat
;
29 import android
.view
.LayoutInflater
;
30 import android
.view
.View
;
31 import android
.view
.View
.OnClickListener
;
32 import android
.view
.ViewGroup
;
33 import android
.widget
.Button
;
34 import android
.widget
.LinearLayout
;
35 import android
.widget
.ProgressBar
;
36 import android
.widget
.TextView
;
38 import org
.strongswan
.android
.R
;
39 import org
.strongswan
.android
.data
.VpnProfile
;
40 import org
.strongswan
.android
.logic
.VpnStateService
;
41 import org
.strongswan
.android
.logic
.VpnStateService
.ErrorState
;
42 import org
.strongswan
.android
.logic
.VpnStateService
.State
;
43 import org
.strongswan
.android
.logic
.VpnStateService
.VpnStateListener
;
45 public class VpnStateFragment
extends Fragment
implements VpnStateListener
47 private static final String KEY_ERROR_CONNECTION_ID
= "error_connection_id";
49 private boolean mVisible
;
50 private TextView mProfileNameView
;
51 private TextView mProfileView
;
52 private TextView mStateView
;
53 private int mColorStateBase
;
54 private int mColorStateError
;
55 private int mColorStateSuccess
;
56 private Button mActionButton
;
57 private ProgressBar mProgress
;
58 private LinearLayout mErrorView
;
59 private TextView mErrorText
;
60 private Button mErrorRetry
;
61 private Button mShowLog
;
62 private long mErrorConnectionID
;
63 private VpnStateService mService
;
64 private final ServiceConnection mServiceConnection
= new ServiceConnection()
67 public void onServiceDisconnected(ComponentName name
)
73 public void onServiceConnected(ComponentName name
, IBinder service
)
75 mService
= ((VpnStateService
.LocalBinder
)service
).getService();
78 mService
.registerListener(VpnStateFragment
.this);
83 private OnClickListener mDisconnectListener
= new OnClickListener()
86 public void onClick(View v
)
90 mService
.disconnect();
96 public void onCreate(Bundle savedInstanceState
)
98 super.onCreate(savedInstanceState
);
100 mColorStateError
= ContextCompat
.getColor(getActivity(), R
.color
.error_text
);
101 mColorStateSuccess
= ContextCompat
.getColor(getActivity(), R
.color
.success_text
);
103 /* bind to the service only seems to work from the ApplicationContext */
104 Context context
= getActivity().getApplicationContext();
105 context
.bindService(new Intent(context
, VpnStateService
.class),
106 mServiceConnection
, Service
.BIND_AUTO_CREATE
);
108 mErrorConnectionID
= 0;
109 if (savedInstanceState
!= null && savedInstanceState
.containsKey(KEY_ERROR_CONNECTION_ID
))
111 mErrorConnectionID
= (Long
)savedInstanceState
.getSerializable(KEY_ERROR_CONNECTION_ID
);
116 public void onSaveInstanceState(Bundle outState
)
118 super.onSaveInstanceState(outState
);
120 outState
.putSerializable(KEY_ERROR_CONNECTION_ID
, mErrorConnectionID
);
124 public View
onCreateView(LayoutInflater inflater
, ViewGroup container
,
125 Bundle savedInstanceState
)
127 View view
= inflater
.inflate(R
.layout
.vpn_state_fragment
, null);
129 mActionButton
= (Button
)view
.findViewById(R
.id
.action
);
130 mActionButton
.setOnClickListener(v
-> clearError());
131 enableActionButton(null);
133 mErrorView
= view
.findViewById(R
.id
.vpn_error
);
134 mErrorText
= view
.findViewById(R
.id
.vpn_error_text
);
135 mErrorRetry
= view
.findViewById(R
.id
.retry
);
136 mShowLog
= view
.findViewById(R
.id
.show_log
);
137 mProgress
= (ProgressBar
)view
.findViewById(R
.id
.progress
);
138 mStateView
= (TextView
)view
.findViewById(R
.id
.vpn_state
);
139 mColorStateBase
= mStateView
.getCurrentTextColor();
140 mProfileView
= (TextView
)view
.findViewById(R
.id
.vpn_profile_label
);
141 mProfileNameView
= (TextView
)view
.findViewById(R
.id
.vpn_profile_name
);
143 mErrorRetry
.setOnClickListener(v
-> {
144 if (mService
!= null)
146 mService
.reconnect();
149 mShowLog
.setOnClickListener(v
-> {
150 Intent intent
= new Intent(getActivity(), LogActivity
.class);
151 startActivity(intent
);
158 public void onStart()
162 if (mService
!= null)
164 mService
.registerListener(this);
174 if (mService
!= null)
176 mService
.unregisterListener(this);
181 public void onDestroy()
184 if (mService
!= null)
186 getActivity().getApplicationContext().unbindService(mServiceConnection
);
191 public void stateChanged()
196 public void updateView()
198 long connectionID
= mService
.getConnectionID();
199 VpnProfile profile
= mService
.getProfile();
200 State state
= mService
.getState();
201 ErrorState error
= mService
.getErrorState();
204 if (getActivity() == null)
211 name
= profile
.getName();
214 if (reportError(connectionID
, name
, error
))
219 mProfileNameView
.setText(name
);
220 mProgress
.setIndeterminate(true);
226 mProgress
.setVisibility(View
.GONE
);
227 enableActionButton(null);
228 mStateView
.setText(R
.string
.state_disabled
);
229 mStateView
.setTextColor(mColorStateBase
);
233 mProgress
.setVisibility(View
.VISIBLE
);
234 enableActionButton(getString(android
.R
.string
.cancel
));
235 mStateView
.setText(R
.string
.state_connecting
);
236 mStateView
.setTextColor(mColorStateBase
);
240 mProgress
.setVisibility(View
.GONE
);
241 enableActionButton(getString(R
.string
.disconnect
));
242 mStateView
.setText(R
.string
.state_connected
);
243 mStateView
.setTextColor(mColorStateSuccess
);
247 mProgress
.setVisibility(View
.VISIBLE
);
248 enableActionButton(null);
249 mStateView
.setText(R
.string
.state_disconnecting
);
250 mStateView
.setTextColor(mColorStateBase
);
255 private boolean reportError(long connectionID
, String name
, ErrorState error
)
257 if (error
== ErrorState
.NO_ERROR
)
259 mErrorView
.setVisibility(View
.GONE
);
262 mErrorConnectionID
= connectionID
;
263 mProfileNameView
.setText(name
);
265 mStateView
.setText(R
.string
.state_error
);
266 mStateView
.setTextColor(mColorStateError
);
267 enableActionButton(getString(android
.R
.string
.cancel
));
269 int retry
= mService
.getRetryIn();
272 mProgress
.setIndeterminate(false);
273 mProgress
.setMax(mService
.getRetryTimeout());
274 mProgress
.setProgress(retry
);
275 mProgress
.setVisibility(View
.VISIBLE
);
276 mStateView
.setText(getResources().getQuantityString(R
.plurals
.retry_in
, retry
, retry
));
278 else if (mService
.getRetryTimeout() <= 0)
280 mProgress
.setVisibility(View
.GONE
);
283 String text
= getString(R
.string
.error_format
, getString(mService
.getErrorText()));
284 mErrorText
.setText(text
);
285 mErrorView
.setVisibility(View
.VISIBLE
);
289 private void showProfile(boolean show
)
291 mProfileView
.setVisibility(show ? View
.VISIBLE
: View
.GONE
);
292 mProfileNameView
.setVisibility(show ? View
.VISIBLE
: View
.GONE
);
295 private void enableActionButton(String text
)
297 mActionButton
.setText(text
);
298 mActionButton
.setEnabled(text
!= null);
299 mActionButton
.setVisibility(text
!= null ? View
.VISIBLE
: View
.GONE
);
302 private void clearError()
304 if (mService
!= null)
306 mService
.disconnect();
307 if (mService
.getConnectionID() == mErrorConnectionID
)
309 mService
.setError(ErrorState
.NO_ERROR
);