]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnStateFragment.java
android: Show a retry button in the error banner
[thirdparty/strongswan.git] / src / frontends / android / app / src / main / java / org / strongswan / android / ui / VpnStateFragment.java
1 /*
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
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 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;
37
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;
46
47 import java.util.ArrayList;
48 import java.util.List;
49
50 public class VpnStateFragment extends Fragment implements VpnStateListener
51 {
52 private static final String KEY_ERROR_CONNECTION_ID = "error_connection_id";
53
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()
69 {
70 @Override
71 public void onServiceDisconnected(ComponentName name)
72 {
73 mService = null;
74 }
75
76 @Override
77 public void onServiceConnected(ComponentName name, IBinder service)
78 {
79 mService = ((VpnStateService.LocalBinder)service).getService();
80 mService.registerListener(VpnStateFragment.this);
81 updateView();
82 }
83 };
84 private OnClickListener mDisconnectListener = new OnClickListener()
85 {
86 @Override
87 public void onClick(View v)
88 {
89 if (mService != null)
90 {
91 mService.disconnect();
92 }
93 }
94 };
95
96 @Override
97 public void onCreate(Bundle savedInstanceState)
98 {
99 super.onCreate(savedInstanceState);
100
101 mColorStateError = ContextCompat.getColor(getActivity(), R.color.error_text);
102 mColorStateSuccess = ContextCompat.getColor(getActivity(), R.color.success_text);
103
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);
108
109 mErrorConnectionID = 0;
110 if (savedInstanceState != null && savedInstanceState.containsKey(KEY_ERROR_CONNECTION_ID))
111 {
112 mErrorConnectionID = (Long)savedInstanceState.getSerializable(KEY_ERROR_CONNECTION_ID);
113 }
114 }
115
116 @Override
117 public void onSaveInstanceState(Bundle outState)
118 {
119 super.onSaveInstanceState(outState);
120
121 outState.putSerializable(KEY_ERROR_CONNECTION_ID, mErrorConnectionID);
122 }
123
124 @Override
125 public View onCreateView(LayoutInflater inflater, ViewGroup container,
126 Bundle savedInstanceState)
127 {
128 View view = inflater.inflate(R.layout.vpn_state_fragment, null);
129
130 mActionButton = (Button)view.findViewById(R.id.action);
131 enableActionButton(null);
132
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);
142
143 mErrorRetry.setOnClickListener(v -> {
144 if (mService != null)
145 {
146 mService.reconnect();
147 }
148 });
149 mDismissError.setOnClickListener(v -> clearError());
150
151 return view;
152 }
153
154 @Override
155 public void onStart()
156 {
157 super.onStart();
158 if (mService != null)
159 {
160 mService.registerListener(this);
161 updateView();
162 }
163 }
164
165 @Override
166 public void onStop()
167 {
168 super.onStop();
169 if (mService != null)
170 {
171 mService.unregisterListener(this);
172 }
173 }
174
175 @Override
176 public void onDestroy()
177 {
178 super.onDestroy();
179 if (mService != null)
180 {
181 getActivity().getApplicationContext().unbindService(mServiceConnection);
182 }
183 }
184
185 @Override
186 public void stateChanged()
187 {
188 updateView();
189 }
190
191 public void updateView()
192 {
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();
198 String name = "";
199
200 if (getActivity() == null)
201 {
202 return;
203 }
204
205 if (profile != null)
206 {
207 name = profile.getName();
208 }
209
210 if (reportError(connectionID, name, error, imcState))
211 {
212 return;
213 }
214
215 mProfileNameView.setText(name);
216
217 switch (state)
218 {
219 case DISABLED:
220 showProfile(false);
221 mProgress.setVisibility(View.GONE);
222 enableActionButton(null);
223 mStateView.setText(R.string.state_disabled);
224 mStateView.setTextColor(mColorStateBase);
225 break;
226 case CONNECTING:
227 showProfile(true);
228 mProgress.setVisibility(View.VISIBLE);
229 enableActionButton(getString(android.R.string.cancel));
230 mStateView.setText(R.string.state_connecting);
231 mStateView.setTextColor(mColorStateBase);
232 break;
233 case CONNECTED:
234 showProfile(true);
235 mProgress.setVisibility(View.GONE);
236 enableActionButton(getString(R.string.disconnect));
237 mStateView.setText(R.string.state_connected);
238 mStateView.setTextColor(mColorStateSuccess);
239 break;
240 case DISCONNECTING:
241 showProfile(true);
242 mProgress.setVisibility(View.VISIBLE);
243 enableActionButton(null);
244 mStateView.setText(R.string.state_disconnecting);
245 mStateView.setTextColor(mColorStateBase);
246 break;
247 }
248 }
249
250 private boolean reportError(long connectionID, String name, ErrorState error, ImcState imcState)
251 {
252 if (error == ErrorState.NO_ERROR)
253 {
254 mErrorView.setVisibility(View.GONE);
255 return false;
256 }
257 mErrorConnectionID = connectionID;
258 mProfileNameView.setText(name);
259 showProfile(true);
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);
267 });
268 mErrorText.setText(getString(R.string.error_format, getString(mService.getErrorText())));
269 mErrorView.setVisibility(View.VISIBLE);
270 return true;
271 }
272
273 private void showProfile(boolean show)
274 {
275 mProfileView.setVisibility(show ? View.VISIBLE : View.GONE);
276 mProfileNameView.setVisibility(show ? View.VISIBLE : View.GONE);
277 }
278
279 private void enableActionButton(String text)
280 {
281 mActionButton.setText(text);
282 mActionButton.setEnabled(text != null);
283 mActionButton.setVisibility(text != null ? View.VISIBLE : View.GONE);
284 mActionButton.setOnClickListener(mDisconnectListener);
285 }
286
287 private void clearError()
288 {
289 if (mService != null)
290 {
291 if (mService.getConnectionID() == mErrorConnectionID)
292 {
293 mService.disconnect();
294 mService.setError(ErrorState.NO_ERROR);
295 }
296 }
297 updateView();
298 }
299 }