android: Replace use of deprecate getColor() method overload
[strongswan.git] / src / frontends / android / app / src / main / java / org / strongswan / android / ui / VpnStateFragment.java
1 /*
2 * Copyright (C) 2012-2013 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 android.app.Fragment;
21 import android.app.ProgressDialog;
22 import android.app.Service;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.Intent;
27 import android.content.ServiceConnection;
28 import android.os.Bundle;
29 import android.os.IBinder;
30 import android.support.v4.content.ContextCompat;
31 import android.support.v7.app.AlertDialog;
32 import android.view.LayoutInflater;
33 import android.view.View;
34 import android.view.View.OnClickListener;
35 import android.view.ViewGroup;
36 import android.widget.Button;
37 import android.widget.TextView;
38
39 import org.strongswan.android.R;
40 import org.strongswan.android.data.VpnProfile;
41 import org.strongswan.android.logic.VpnStateService;
42 import org.strongswan.android.logic.VpnStateService.ErrorState;
43 import org.strongswan.android.logic.VpnStateService.State;
44 import org.strongswan.android.logic.VpnStateService.VpnStateListener;
45 import org.strongswan.android.logic.imc.ImcState;
46 import org.strongswan.android.logic.imc.RemediationInstruction;
47
48 import java.util.ArrayList;
49 import java.util.List;
50
51 public class VpnStateFragment extends Fragment implements VpnStateListener
52 {
53 private static final String KEY_ERROR_CONNECTION_ID = "error_connection_id";
54 private static final String KEY_DISMISSED_CONNECTION_ID = "dismissed_connection_id";
55
56 private TextView mProfileNameView;
57 private TextView mProfileView;
58 private TextView mStateView;
59 private int mColorStateBase;
60 private int mColorStateError;
61 private int mColorStateSuccess;
62 private Button mActionButton;
63 private ProgressDialog mConnectDialog;
64 private ProgressDialog mDisconnectDialog;
65 private ProgressDialog mProgressDialog;
66 private AlertDialog mErrorDialog;
67 private long mErrorConnectionID;
68 private long mDismissedConnectionID;
69 private VpnStateService mService;
70 private final ServiceConnection mServiceConnection = new ServiceConnection()
71 {
72 @Override
73 public void onServiceDisconnected(ComponentName name)
74 {
75 mService = null;
76 }
77
78 @Override
79 public void onServiceConnected(ComponentName name, IBinder service)
80 {
81 mService = ((VpnStateService.LocalBinder)service).getService();
82 mService.registerListener(VpnStateFragment.this);
83 updateView();
84 }
85 };
86
87 @Override
88 public void onCreate(Bundle savedInstanceState)
89 {
90 super.onCreate(savedInstanceState);
91
92 mColorStateError = ContextCompat.getColor(getActivity(), R.color.error_text);
93 mColorStateSuccess = ContextCompat.getColor(getActivity(), R.color.success_text);
94
95 /* bind to the service only seems to work from the ApplicationContext */
96 Context context = getActivity().getApplicationContext();
97 context.bindService(new Intent(context, VpnStateService.class),
98 mServiceConnection, Service.BIND_AUTO_CREATE);
99
100 mErrorConnectionID = 0;
101 mDismissedConnectionID = 0;
102 if (savedInstanceState != null && savedInstanceState.containsKey(KEY_ERROR_CONNECTION_ID))
103 {
104 mErrorConnectionID = (Long)savedInstanceState.getSerializable(KEY_ERROR_CONNECTION_ID);
105 mDismissedConnectionID = (Long)savedInstanceState.getSerializable(KEY_DISMISSED_CONNECTION_ID);
106 }
107 }
108
109 @Override
110 public void onSaveInstanceState(Bundle outState)
111 {
112 super.onSaveInstanceState(outState);
113
114 outState.putSerializable(KEY_ERROR_CONNECTION_ID, mErrorConnectionID);
115 outState.putSerializable(KEY_DISMISSED_CONNECTION_ID, mDismissedConnectionID);
116 }
117
118 @Override
119 public View onCreateView(LayoutInflater inflater, ViewGroup container,
120 Bundle savedInstanceState)
121 {
122 View view = inflater.inflate(R.layout.vpn_state_fragment, null);
123
124 mActionButton = (Button)view.findViewById(R.id.action);
125 mActionButton.setOnClickListener(new OnClickListener()
126 {
127 @Override
128 public void onClick(View v)
129 {
130 if (mService != null)
131 {
132 mService.disconnect();
133 }
134 }
135 });
136 enableActionButton(false);
137
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 return view;
144 }
145
146 @Override
147 public void onStart()
148 {
149 super.onStart();
150 if (mService != null)
151 {
152 mService.registerListener(this);
153 updateView();
154 }
155 }
156
157 @Override
158 public void onStop()
159 {
160 super.onStop();
161 if (mService != null)
162 {
163 mService.unregisterListener(this);
164 }
165 hideErrorDialog();
166 hideProgressDialog();
167 }
168
169 @Override
170 public void onDestroy()
171 {
172 super.onDestroy();
173 if (mService != null)
174 {
175 getActivity().getApplicationContext().unbindService(mServiceConnection);
176 }
177 }
178
179 @Override
180 public void stateChanged()
181 {
182 updateView();
183 }
184
185 public void updateView()
186 {
187 long connectionID = mService.getConnectionID();
188 VpnProfile profile = mService.getProfile();
189 State state = mService.getState();
190 ErrorState error = mService.getErrorState();
191 ImcState imcState = mService.getImcState();
192 String name = "", gateway = "";
193
194 if (profile != null)
195 {
196 name = profile.getName();
197 gateway = profile.getGateway();
198 }
199
200 if (reportError(connectionID, name, error, imcState))
201 {
202 return;
203 }
204
205 enableActionButton(false);
206 mProfileNameView.setText(name);
207
208 switch (state)
209 {
210 case DISABLED:
211 showProfile(false);
212 hideProgressDialog();
213 mStateView.setText(R.string.state_disabled);
214 mStateView.setTextColor(mColorStateBase);
215 break;
216 case CONNECTING:
217 showProfile(true);
218 showConnectDialog(name, gateway);
219 mStateView.setText(R.string.state_connecting);
220 mStateView.setTextColor(mColorStateBase);
221 break;
222 case CONNECTED:
223 showProfile(true);
224 hideProgressDialog();
225 enableActionButton(true);
226 mStateView.setText(R.string.state_connected);
227 mStateView.setTextColor(mColorStateSuccess);
228 break;
229 case DISCONNECTING:
230 showProfile(true);
231 showDisconnectDialog(name);
232 mStateView.setText(R.string.state_disconnecting);
233 mStateView.setTextColor(mColorStateBase);
234 break;
235 }
236 }
237
238 private boolean reportError(long connectionID, String name, ErrorState error, ImcState imcState)
239 {
240 if (connectionID > mDismissedConnectionID)
241 { /* report error if it hasn't been dismissed yet */
242 mErrorConnectionID = connectionID;
243 }
244 else
245 { /* ignore all other errors */
246 error = ErrorState.NO_ERROR;
247 }
248 if (error == ErrorState.NO_ERROR)
249 {
250 hideErrorDialog();
251 return false;
252 }
253 else if (mErrorDialog != null)
254 { /* we already show the dialog */
255 return true;
256 }
257 hideProgressDialog();
258 mProfileNameView.setText(name);
259 showProfile(true);
260 enableActionButton(false);
261 mStateView.setText(R.string.state_error);
262 mStateView.setTextColor(mColorStateError);
263 switch (error)
264 {
265 case AUTH_FAILED:
266 if (imcState == ImcState.BLOCK)
267 {
268 showErrorDialog(R.string.error_assessment_failed);
269 }
270 else
271 {
272 showErrorDialog(R.string.error_auth_failed);
273 }
274 break;
275 case PEER_AUTH_FAILED:
276 showErrorDialog(R.string.error_peer_auth_failed);
277 break;
278 case LOOKUP_FAILED:
279 showErrorDialog(R.string.error_lookup_failed);
280 break;
281 case UNREACHABLE:
282 showErrorDialog(R.string.error_unreachable);
283 break;
284 default:
285 showErrorDialog(R.string.error_generic);
286 break;
287 }
288 return true;
289 }
290
291 private void showProfile(boolean show)
292 {
293 mProfileView.setVisibility(show ? View.VISIBLE : View.GONE);
294 mProfileNameView.setVisibility(show ? View.VISIBLE : View.GONE);
295 }
296
297 private void enableActionButton(boolean enable)
298 {
299 mActionButton.setEnabled(enable);
300 mActionButton.setVisibility(enable ? View.VISIBLE : View.GONE);
301 }
302
303 private void hideProgressDialog()
304 {
305 if (mProgressDialog != null)
306 {
307 mProgressDialog.dismiss();
308 mProgressDialog = null;
309 mDisconnectDialog = mConnectDialog = null;
310 }
311 }
312
313 private void hideErrorDialog()
314 {
315 if (mErrorDialog != null)
316 {
317 mErrorDialog.dismiss();
318 mErrorDialog = null;
319 }
320 }
321
322 private void clearError()
323 {
324 if (mService != null)
325 {
326 mService.disconnect();
327 }
328 mDismissedConnectionID = mErrorConnectionID;
329 updateView();
330 }
331
332 private void showConnectDialog(String profile, String gateway)
333 {
334 if (mConnectDialog != null)
335 { /* already showing the dialog */
336 return;
337 }
338 hideProgressDialog();
339 mConnectDialog = new ProgressDialog(getActivity());
340 mConnectDialog.setTitle(String.format(getString(R.string.connecting_title), profile));
341 mConnectDialog.setMessage(String.format(getString(R.string.connecting_message), gateway));
342 mConnectDialog.setIndeterminate(true);
343 mConnectDialog.setCancelable(false);
344 mConnectDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
345 getString(android.R.string.cancel),
346 new DialogInterface.OnClickListener()
347 {
348 @Override
349 public void onClick(DialogInterface dialog, int which)
350 {
351 if (mService != null)
352 {
353 mService.disconnect();
354 }
355 }
356 });
357 mConnectDialog.show();
358 mProgressDialog = mConnectDialog;
359 }
360
361 private void showDisconnectDialog(String profile)
362 {
363 if (mDisconnectDialog != null)
364 { /* already showing the dialog */
365 return;
366 }
367 hideProgressDialog();
368 mDisconnectDialog = new ProgressDialog(getActivity());
369 mDisconnectDialog.setMessage(getString(R.string.state_disconnecting));
370 mDisconnectDialog.setIndeterminate(true);
371 mDisconnectDialog.setCancelable(false);
372 mDisconnectDialog.show();
373 mProgressDialog = mDisconnectDialog;
374 }
375
376 private void showErrorDialog(int textid)
377 {
378 final List<RemediationInstruction> instructions = mService.getRemediationInstructions();
379 final boolean show_instructions = mService.getImcState() == ImcState.BLOCK && !instructions.isEmpty();
380 int text = show_instructions ? R.string.show_remediation_instructions : R.string.show_log;
381
382 mErrorDialog = new AlertDialog.Builder(getActivity())
383 .setMessage(getString(R.string.error_introduction) + " " + getString(textid))
384 .setCancelable(false)
385 .setNeutralButton(text, new DialogInterface.OnClickListener()
386 {
387 @Override
388 public void onClick(DialogInterface dialog, int which)
389 {
390 clearError();
391 dialog.dismiss();
392 Intent intent;
393 if (show_instructions)
394 {
395 intent = new Intent(getActivity(), RemediationInstructionsActivity.class);
396 intent.putParcelableArrayListExtra(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS,
397 new ArrayList<RemediationInstruction>(instructions));
398 }
399 else
400 {
401 intent = new Intent(getActivity(), LogActivity.class);
402 }
403 startActivity(intent);
404 }
405 })
406 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
407 {
408 @Override
409 public void onClick(DialogInterface dialog, int id)
410 {
411 clearError();
412 dialog.dismiss();
413 }
414 }).create();
415 mErrorDialog.setOnDismissListener(new DialogInterface.OnDismissListener()
416 {
417 @Override
418 public void onDismiss(DialogInterface dialog)
419 {
420 mErrorDialog = null;
421 }
422 });
423 mErrorDialog.show();
424 }
425 }