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
;
44 import org
.strongswan
.android
.logic
.imc
.ImcState
;
45 import org
.strongswan
.android
.logic
.imc
.RemediationInstruction
;
47 import java
.util
.ArrayList
;
48 import java
.util
.List
;
50 public class VpnStateFragment
extends Fragment
implements VpnStateListener
52 private static final String KEY_ERROR_CONNECTION_ID
= "error_connection_id";
54 private TextView mProfileNameView
;
55 private TextView mProfileView
;
56 private TextView mStateView
;
57 private int mColorStateBase
;
58 private int mColorStateError
;
59 private int mColorStateSuccess
;
60 private Button mActionButton
;
61 private ProgressBar mProgress
;
62 private LinearLayout mErrorView
;
63 private TextView mErrorText
;
64 private Button mErrorRetry
;
65 private Button mDismissError
;
66 private long mErrorConnectionID
;
67 private VpnStateService mService
;
68 private final ServiceConnection mServiceConnection
= new ServiceConnection()
71 public void onServiceDisconnected(ComponentName name
)
77 public void onServiceConnected(ComponentName name
, IBinder service
)
79 mService
= ((VpnStateService
.LocalBinder
)service
).getService();
80 mService
.registerListener(VpnStateFragment
.this);
84 private OnClickListener mDisconnectListener
= new OnClickListener()
87 public void onClick(View v
)
91 mService
.disconnect();
97 public void onCreate(Bundle savedInstanceState
)
99 super.onCreate(savedInstanceState
);
101 mColorStateError
= ContextCompat
.getColor(getActivity(), R
.color
.error_text
);
102 mColorStateSuccess
= ContextCompat
.getColor(getActivity(), R
.color
.success_text
);
104 /* bind to the service only seems to work from the ApplicationContext */
105 Context context
= getActivity().getApplicationContext();
106 context
.bindService(new Intent(context
, VpnStateService
.class),
107 mServiceConnection
, Service
.BIND_AUTO_CREATE
);
109 mErrorConnectionID
= 0;
110 if (savedInstanceState
!= null && savedInstanceState
.containsKey(KEY_ERROR_CONNECTION_ID
))
112 mErrorConnectionID
= (Long
)savedInstanceState
.getSerializable(KEY_ERROR_CONNECTION_ID
);
117 public void onSaveInstanceState(Bundle outState
)
119 super.onSaveInstanceState(outState
);
121 outState
.putSerializable(KEY_ERROR_CONNECTION_ID
, mErrorConnectionID
);
125 public View
onCreateView(LayoutInflater inflater
, ViewGroup container
,
126 Bundle savedInstanceState
)
128 View view
= inflater
.inflate(R
.layout
.vpn_state_fragment
, null);
130 mActionButton
= (Button
)view
.findViewById(R
.id
.action
);
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 mDismissError
= view
.findViewById(R
.id
.dismiss_error
);
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 mDismissError
.setOnClickListener(v
-> clearError());
155 public void onStart()
158 if (mService
!= null)
160 mService
.registerListener(this);
169 if (mService
!= null)
171 mService
.unregisterListener(this);
176 public void onDestroy()
179 if (mService
!= null)
181 getActivity().getApplicationContext().unbindService(mServiceConnection
);
186 public void stateChanged()
191 public void updateView()
193 long connectionID
= mService
.getConnectionID();
194 VpnProfile profile
= mService
.getProfile();
195 State state
= mService
.getState();
196 ErrorState error
= mService
.getErrorState();
197 ImcState imcState
= mService
.getImcState();
200 if (getActivity() == null)
207 name
= profile
.getName();
210 if (reportError(connectionID
, name
, error
, imcState
))
215 mProfileNameView
.setText(name
);
221 mProgress
.setVisibility(View
.GONE
);
222 enableActionButton(null);
223 mStateView
.setText(R
.string
.state_disabled
);
224 mStateView
.setTextColor(mColorStateBase
);
228 mProgress
.setVisibility(View
.VISIBLE
);
229 enableActionButton(getString(android
.R
.string
.cancel
));
230 mStateView
.setText(R
.string
.state_connecting
);
231 mStateView
.setTextColor(mColorStateBase
);
235 mProgress
.setVisibility(View
.GONE
);
236 enableActionButton(getString(R
.string
.disconnect
));
237 mStateView
.setText(R
.string
.state_connected
);
238 mStateView
.setTextColor(mColorStateSuccess
);
242 mProgress
.setVisibility(View
.VISIBLE
);
243 enableActionButton(null);
244 mStateView
.setText(R
.string
.state_disconnecting
);
245 mStateView
.setTextColor(mColorStateBase
);
250 private boolean reportError(long connectionID
, String name
, ErrorState error
, ImcState imcState
)
252 if (error
== ErrorState
.NO_ERROR
)
254 mErrorView
.setVisibility(View
.GONE
);
257 mErrorConnectionID
= connectionID
;
258 mProfileNameView
.setText(name
);
260 mProgress
.setVisibility(View
.GONE
);
261 mStateView
.setText(R
.string
.state_error
);
262 mStateView
.setTextColor(mColorStateError
);
263 enableActionButton(getString(R
.string
.show_log
));
264 mActionButton
.setOnClickListener(v
-> {
265 Intent intent
= new Intent(getActivity(), LogActivity
.class);
266 startActivity(intent
);
268 mErrorText
.setText(getString(R
.string
.error_format
, getString(mService
.getErrorText())));
269 mErrorView
.setVisibility(View
.VISIBLE
);
273 private void showProfile(boolean show
)
275 mProfileView
.setVisibility(show ? View
.VISIBLE
: View
.GONE
);
276 mProfileNameView
.setVisibility(show ? View
.VISIBLE
: View
.GONE
);
279 private void enableActionButton(String text
)
281 mActionButton
.setText(text
);
282 mActionButton
.setEnabled(text
!= null);
283 mActionButton
.setVisibility(text
!= null ? View
.VISIBLE
: View
.GONE
);
284 mActionButton
.setOnClickListener(mDisconnectListener
);
287 private void clearError()
289 if (mService
!= null)
291 if (mService
.getConnectionID() == mErrorConnectionID
)
293 mService
.disconnect();
294 mService
.setError(ErrorState
.NO_ERROR
);