From c3a9d580a8428809aa001129ce78c93ed3ee72a8 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 11:10:10 -0600 Subject: Show notification while VPN connection in progress and when VPN connection lost --- src/se/leap/openvpn/OpenVpnService.java | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/se/leap/openvpn/OpenVpnService.java b/src/se/leap/openvpn/OpenVpnService.java index 08a5d62e..b5653d4d 100644 --- a/src/se/leap/openvpn/OpenVpnService.java +++ b/src/se/leap/openvpn/OpenVpnService.java @@ -67,6 +67,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac private int mMtu; private String mLocalIPv6=null; private NetworkSateReceiver mNetworkStateReceiver; + private NotificationManager mNotificationManager; private boolean mDisplayBytecount=false; @@ -118,9 +119,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac } } - private void showNotification(String msg, String tickerText, boolean lowpriority, long when) { + private void showNotification(String msg, String tickerText, boolean lowpriority, long when, boolean persistant) { String ns = Context.NOTIFICATION_SERVICE; - NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns); + mNotificationManager = (NotificationManager) getSystemService(ns); int icon = R.drawable.ic_stat_vpn; @@ -129,7 +130,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac nbuilder.setContentTitle(getString(R.string.notifcation_title,mProfile.mName)); nbuilder.setContentText(msg); nbuilder.setOnlyAlertOnce(true); - nbuilder.setOngoing(true); + nbuilder.setOngoing(persistant); nbuilder.setContentIntent(getLogPendingIntent()); nbuilder.setSmallIcon(icon); if(when !=0) @@ -146,7 +147,6 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac mNotificationManager.notify(OPENVPN_STATUS, notification); - startForeground(OPENVPN_STATUS, notification); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @@ -483,26 +483,16 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac if(mProcessThread==null) return; - // Display byte count only after being connected - - if("BYTECOUNT".equals(state)) { - if(mDisplayBytecount) { - //showNotification(logmessage,null,true,mConnecttime); - } - } else { - if("CONNECTED".equals(state)) { - mDisplayBytecount = true; - mConnecttime = System.currentTimeMillis(); - } else { - mDisplayBytecount = false; - } + if("CONNECTED".equals(state)) { + mNotificationManager.cancel(OPENVPN_STATUS); + } else if(!"BYTECOUNT".equals(state)) { // Other notifications are shown, // This also mean we are no longer connected, ignore bytecount messages until next // CONNECTED String ticker = getString(resid); - //showNotification(getString(resid) +" " + logmessage,ticker,false,0); - + boolean persist = ("NOPROCESS".equals(state)) ? false : true; + showNotification(getString(resid) +" " + logmessage,ticker,false,0,persist); } } -- cgit v1.2.3 From 25313f3f444516a1aad2f4687792bc9073601920 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 11:15:50 -0600 Subject: Don't send byte count messages to the state listeners --- src/se/leap/openvpn/OpenVPN.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/se/leap/openvpn/OpenVPN.java b/src/se/leap/openvpn/OpenVPN.java index 152cf2d8..3ffc47cb 100644 --- a/src/se/leap/openvpn/OpenVPN.java +++ b/src/se/leap/openvpn/OpenVPN.java @@ -204,10 +204,10 @@ public class OpenVPN { mLaststate= state; mLaststatemsg = msg; mLastStateresid = resid; - } - for (StateListener sl : stateListener) { - sl.updateState(state,msg,resid); + for (StateListener sl : stateListener) { + sl.updateState(state,msg,resid); + } } } -- cgit v1.2.3 From 6614dface821c5f975dba47bc6150783c25ee468 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 11:17:03 -0600 Subject: Better VPN connection state messages --- src/se/leap/leapclient/Dashboard.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 1b6b8e38..b58f4952 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -427,16 +427,25 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public void updateState(final String state, final String logmessage, final int localizedResId) { // Note: "states" are not organized anywhere...collected state strings: - // NOPROCESS,NONETWORK,BYTECOUNT,AUTH_FAILED + some parsing thing ( WAIT(?),AUTH,GET_CONFIG,ASSIGN_IP,CONNECTED(?) ) + // NOPROCESS,NONETWORK,BYTECOUNT,AUTH_FAILED + some parsing thing ( WAIT(?),AUTH,GET_CONFIG,ASSIGN_IP,CONNECTED,SIGINT ) runOnUiThread(new Runnable() { @Override public void run() { if (eipStatus != null) { - String prefix = getString(localizedResId) + ":"; - if (state.equals("BYTECOUNT") || state.equals("NOPROCESS")) - prefix = ""; - eipStatus.setText(prefix + logmessage); + String statusMessage = ""; + String prefix = getString(localizedResId); + if (state.equals("CONNECTED")){ + statusMessage = "Connection Secure"; + } else if (state.equals("BYTECOUNT")) { + statusMessage = logmessage; + } else if (state.equals("NOPROCESS") || state.equals("EXITING")) { + statusMessage = "Not running! Connection not secure!"; + } else { + statusMessage = prefix + logmessage; + } + + eipStatus.setText(statusMessage); } } }); -- cgit v1.2.3 From e85eb39a9cfa209eb5503657d9724d1eebd2be0b Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 11:23:21 -0600 Subject: Only parse eip-services.json if the serial has incremented --- src/se/leap/leapclient/ConfigHelper.java | 23 +++++++++++++++++++++++ src/se/leap/leapclient/Dashboard.java | 1 + src/se/leap/leapclient/EIP.java | 21 +++++++++++++++++---- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index c5a37be5..0c589c41 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -49,6 +49,7 @@ public class ConfigHelper { LOG_OUT = "logOut", DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", API_VERSION_KEY = "api_version", + API_RETURN_SERIAL_KEY = "serial", RESULT_KEY = "result", RECEIVER_KEY = "receiver", PROVIDER_KEY = "provider", @@ -58,6 +59,7 @@ public class ConfigHelper { CERT_KEY = "cert", KEY_KEY = "key", EIP_SERVICE_KEY = "eip", + EIP_PARSED_SERIAL = "eip_parsed_serial", TYPE_OF_CERTIFICATE = "type_of_certificate", ANON_CERTIFICATE = "anon_certificate", AUTHED_CERTIFICATE = "authed_certificate", @@ -161,6 +163,17 @@ public class ConfigHelper { shared_preferences_editor.commit(); } + /** + * Saves an int into class scope Shared Preferences + * + * @param shared_preferences_key + * @param value + */ + protected static void saveSharedPref(String shared_preferences_key, int value) { + SharedPreferences.Editor shared_preferences_editor = shared_preferences.edit(); + shared_preferences_editor.putInt(shared_preferences_key, value).commit(); + } + /** * Gets String object from class scope Shared Preferences * @param shared_preferences_key @@ -199,6 +212,16 @@ public class ConfigHelper { } return value; } + + /** + * Get an int from SharedPreferences + * + * @param shared_preferences_key Key to retrieve + * @return The value for the key or 0 + */ + protected static int getIntFromSharedPref(String shared_preferences_key) { + return shared_preferences.getInt(shared_preferences_key, 0); + } /* * This method defaults to false. diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index b58f4952..6634479e 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -99,6 +99,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf protected void onActivityResult(int requestCode, int resultCode, Intent data){ if ( requestCode == CONFIGURE_LEAP ) { if ( resultCode == RESULT_OK ){ + startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); buildDashboard(); if(data != null && data.hasExtra(ConfigHelper.LOG_IN)) { View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index b86a2a4a..5057732e 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -54,6 +54,7 @@ public final class EIP extends IntentService { // Used to store actions to "resume" onServiceConnection private static String mPending = null; + private static int parsedEipSerial; private static JSONObject eipDefinition = null; private static OVPNGateway activeGateway = null; @@ -70,6 +71,7 @@ public final class EIP extends IntentService { try { eipDefinition = ConfigHelper.getJsonFromSharedPref(ConfigHelper.EIP_SERVICE_KEY); + parsedEipSerial = ConfigHelper.getIntFromSharedPref(ConfigHelper.EIP_PARSED_SERIAL); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -224,7 +226,8 @@ public final class EIP extends IntentService { // TODO Auto-generated catch block e.printStackTrace(); } - updateGateways(); + if (eipDefinition.optInt("serial") > parsedEipSerial) + updateGateways(); } /** @@ -274,6 +277,8 @@ public final class EIP extends IntentService { e.printStackTrace(); } } + + ConfigHelper.saveSharedPref(ConfigHelper.EIP_PARSED_SERIAL, eipDefinition.optInt(ConfigHelper.API_RETURN_SERIAL_KEY)); } /** @@ -287,6 +292,7 @@ public final class EIP extends IntentService { private String TAG = "OVPNGateway"; + private String mName; private VpnProfile mVpnProfile; private JSONObject mGateway; private HashMap>> options = new HashMap>>(); @@ -299,17 +305,24 @@ public final class EIP extends IntentService { * @param name The hostname of the gateway to inflate */ private OVPNGateway(String name){ + mName = name; + + this.loadVpnProfile(); + } + + private void loadVpnProfile() { ProfileManager vpl = ProfileManager.getInstance(context); try { - if ( name == "first" ) { - name = vpl.getProfiles().iterator().next().mName; + if ( mName == "first" ) { + mName = vpl.getProfiles().iterator().next().mName; } - mVpnProfile = vpl.getProfileByName(name); + mVpnProfile = vpl.getProfileByName(mName); } catch (NoSuchElementException e) { updateEIPService(); + this.loadVpnProfile(); // FIXME catch infinite loops } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 437183f283e61da878aded001fb78e8e62aa9da6 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 13:15:52 -0600 Subject: Use non-blocking logic for EIP switch Includes AlertDialog if the user attempts to stop EIP while a connection is being established --- res/values/strings.xml | 4 +++ src/se/leap/leapclient/Dashboard.java | 59 +++++++++++++++++++++++++---------- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 3a178037..09819809 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -314,5 +314,9 @@ Didn\'t logged out. Your own cert has been correctly downloaded. Your own cert has incorrectly been downloaded. + Cancel connection? + There is a connection attempt in progress. Do you wish to cancel it? + Yes + No diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 6634479e..ebce35ed 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -55,7 +55,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf private View eipDetail; private TextView eipStatus; - private boolean mEipWait = false; + private boolean mEipStartPending = false; private boolean authed = false; public ProviderAPIResultReceiver providerAPI_result_receiver; @@ -187,23 +187,50 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf eipSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (!mEipWait){ - buttonView.setClickable(false); - mEipWait = true; - - Intent vpnIntent; - if (isChecked){ - vpnIntent = new Intent(EIP.ACTION_START_EIP); + + if (isChecked){ + mEipStartPending = true; + eipCommand(EIP.ACTION_START_EIP); + } else { + if (mEipStartPending){ + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getAppContext()); + alertBuilder.setTitle(getResources().getString(R.string.eip_cancel_connect_title)); + alertBuilder + .setMessage(getResources().getString(R.string.eip_cancel_connect_text)) + .setPositiveButton(getResources().getString(R.string.eip_cancel_connect_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + eipCommand(EIP.ACTION_STOP_EIP); + } + }) + .setNegativeButton(getResources().getString(R.string.eip_cancel_connect_false), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + eipSwitch.setChecked(true); + } + }) + .show(); } else { - vpnIntent = new Intent(EIP.ACTION_STOP_EIP); + eipCommand(EIP.ACTION_STOP_EIP); } - vpnIntent.putExtra(ConfigHelper.RECEIVER_TAG, mEIPReceiver); - startService(vpnIntent); } } }); } + /** + * Send a command to EIP + * + * @param action A valid String constant from EIP class representing an Intent + * filter for the EIP class + */ + private void eipCommand(String action){ + // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? + Intent vpnIntent = new Intent(action); + vpnIntent.putExtra(ConfigHelper.RECEIVER_TAG, mEIPReceiver); + startService(vpnIntent); + } + /** * Expands the EIP Dashboard component for extra details view. * Called by onClick property in client_dashboard.xml layout. @@ -434,18 +461,22 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public void run() { if (eipStatus != null) { + boolean switchState = true; String statusMessage = ""; String prefix = getString(localizedResId); if (state.equals("CONNECTED")){ statusMessage = "Connection Secure"; + mEipStartPending = false; } else if (state.equals("BYTECOUNT")) { statusMessage = logmessage; } else if (state.equals("NOPROCESS") || state.equals("EXITING")) { statusMessage = "Not running! Connection not secure!"; + switchState = false; } else { statusMessage = prefix + logmessage; } + eipSwitch.setChecked(switchState); eipStatus.setText(statusMessage); } } @@ -474,7 +505,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf super.onReceiveResult(resultCode, resultData); String request = resultData.getString(ConfigHelper.REQUEST_TAG); - mEipWait = true; boolean checked = false; if (request == EIP.ACTION_IS_EIP_RUNNING) { @@ -515,10 +545,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } } - Switch eipS = ((Switch) mDashboard.findViewById(R.id.eipSwitch)); - eipS.setChecked(checked); - eipS.setClickable(true); - mEipWait = false; + eipSwitch.setChecked(checked); } } } -- cgit v1.2.3 From f9131ce775b180cee3fa8ec1ac52290a7f58d1ef Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 18:26:31 -0600 Subject: Refactor EIP UI and control logic out of Dashboard into a Fragment --- res/layout/client_dashboard.xml | 11 +- res/layout/eip_overview.xml | 76 -------- res/layout/eip_service_fragment.xml | 74 ++++++++ src/se/leap/leapclient/Dashboard.java | 241 +------------------------ src/se/leap/leapclient/EipServiceFragment.java | 234 ++++++++++++++++++++++++ 5 files changed, 319 insertions(+), 317 deletions(-) delete mode 100644 res/layout/eip_overview.xml create mode 100644 res/layout/eip_service_fragment.xml create mode 100644 src/se/leap/leapclient/EipServiceFragment.java diff --git a/res/layout/client_dashboard.xml b/res/layout/client_dashboard.xml index 9d9b7a40..9f05cfbc 100644 --- a/res/layout/client_dashboard.xml +++ b/res/layout/client_dashboard.xml @@ -65,15 +65,6 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="0.11" - android:orientation="vertical" > - - - - + android:orientation="vertical" /> \ No newline at end of file diff --git a/res/layout/eip_overview.xml b/res/layout/eip_overview.xml deleted file mode 100644 index 738c82ef..00000000 --- a/res/layout/eip_overview.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/layout/eip_service_fragment.xml b/res/layout/eip_service_fragment.xml new file mode 100644 index 00000000..8f7c1d22 --- /dev/null +++ b/res/layout/eip_service_fragment.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index ebce35ed..4cd517a9 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -6,14 +6,12 @@ import org.json.JSONException; import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; -import se.leap.openvpn.LogWindow; import se.leap.openvpn.MainActivity; -import se.leap.openvpn.OpenVPN; -import se.leap.openvpn.OpenVPN.StateListener; import android.app.Activity; import android.app.AlertDialog; import android.app.DialogFragment; import android.app.Fragment; +import android.app.FragmentManager; import android.app.FragmentTransaction; import android.app.ProgressDialog; import android.content.Context; @@ -22,15 +20,10 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; -import android.os.ResultReceiver; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.view.ViewStub; -import android.widget.CompoundButton; -import android.widget.RelativeLayout; -import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; @@ -40,26 +33,23 @@ import android.widget.Toast; * * @author Sean Leonard */ -public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface,Receiver,StateListener { +public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface,Receiver { protected static final int CONFIGURE_LEAP = 0; + private static final String TAG_EIP_FRAGMENT = "EIP_DASHBOARD_FRAGMENT"; + private ProgressDialog mProgressDialog; + private static Context app; private static SharedPreferences preferences; private static Provider provider; private TextView providerNameTV; - private TextView eipTypeTV; - private Switch eipSwitch; - private View eipDetail; - private TextView eipStatus; - - private boolean mEipStartPending = false; + private boolean authed = false; public ProviderAPIResultReceiver providerAPI_result_receiver; - private EIPReceiver mEIPReceiver; @Override protected void onCreate(Bundle savedInstanceState) { @@ -77,23 +67,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf else buildDashboard(); } - - @Override - protected void onStop() { - super.onStop(); - if (provider != null) - if (provider.hasEIP() && provider.getEIPType() == "OpenVPN") - OpenVPN.removeStateListener(this); - } - - @Override - protected void onResume() { - super.onResume(); - - if (provider != null) - if (provider.hasEIP() && provider.getEIPType() == "OpenVPN") - OpenVPN.addStateListener(this); - } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data){ @@ -150,111 +123,13 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf providerNameTV.setText(provider.getName()); providerNameTV.setTextSize(28); - if ( provider.hasEIP() ){ - startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); - if (provider.getEIPType() == "OpenVPN") - OpenVPN.addStateListener(this); - serviceItemEIP(); + FragmentManager fragMan = getFragmentManager(); + if ( provider.hasEIP() && fragMan.findFragmentByTag(TAG_EIP_FRAGMENT) == null){ + EipServiceFragment eipFragment = new EipServiceFragment(); + fragMan.beginTransaction().add(R.id.servicesCollection, eipFragment, TAG_EIP_FRAGMENT).commit(); } } - /** - * Builds the UI for the EIP service Dashboard component - */ - private void serviceItemEIP() { - mEIPReceiver = new EIPReceiver(new Handler()); - mEIPReceiver.setReceiver(this); - - Intent intent = new Intent(this,EIP.class); - intent.setAction(EIP.ACTION_IS_EIP_RUNNING); - intent.putExtra(ConfigHelper.RECEIVER_TAG, mEIPReceiver); - startService(intent); - - ViewStub eip_overview_stub = ((ViewStub) findViewById(R.id.eipOverviewStub)); - if(eip_overview_stub != null) - eip_overview_stub.inflate(); - - eipTypeTV = (TextView) findViewById(R.id.eipType); - eipTypeTV.setText(provider.getEIPType()); - - eipDetail = ((RelativeLayout) findViewById(R.id.eipDetail)); - View eipSettings = findViewById(R.id.eipSettings); - eipSettings.setVisibility(View.GONE); // FIXME too! - eipDetail.setVisibility(View.VISIBLE); - eipStatus = (TextView) findViewById(R.id.eipStatus); - - eipSwitch = (Switch) findViewById(R.id.eipSwitch); - eipSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - - if (isChecked){ - mEipStartPending = true; - eipCommand(EIP.ACTION_START_EIP); - } else { - if (mEipStartPending){ - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getAppContext()); - alertBuilder.setTitle(getResources().getString(R.string.eip_cancel_connect_title)); - alertBuilder - .setMessage(getResources().getString(R.string.eip_cancel_connect_text)) - .setPositiveButton(getResources().getString(R.string.eip_cancel_connect_cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - eipCommand(EIP.ACTION_STOP_EIP); - } - }) - .setNegativeButton(getResources().getString(R.string.eip_cancel_connect_false), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - eipSwitch.setChecked(true); - } - }) - .show(); - } else { - eipCommand(EIP.ACTION_STOP_EIP); - } - } - } - }); - } - - /** - * Send a command to EIP - * - * @param action A valid String constant from EIP class representing an Intent - * filter for the EIP class - */ - private void eipCommand(String action){ - // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? - Intent vpnIntent = new Intent(action); - vpnIntent.putExtra(ConfigHelper.RECEIVER_TAG, mEIPReceiver); - startService(vpnIntent); - } - - /** - * Expands the EIP Dashboard component for extra details view. - * Called by onClick property in client_dashboard.xml layout. - * - * @param view (Unused) The View calling this method by its onClick property - */ - public void toggleEipOverview(View view) { - if (eipDetail.isShown()) - eipDetail.setVisibility(View.GONE); - else - eipDetail.setVisibility(View.VISIBLE); - } - - /** - * Launches the se.leap.openvpn.LogWindow Activity showing detailed OpenVPN log - * - * @param view (Unused) The View calling this method by its onClick property - */ - public void showEIPLog(View view){ - Intent intent = new Intent(getBaseContext(),LogWindow.class); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - startActivity(intent); - } - @Override public boolean onPrepareOptionsMenu(Menu menu) { JSONObject provider_json; @@ -452,100 +327,4 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf return app; } - @Override - public void updateState(final String state, final String logmessage, final int localizedResId) { - // Note: "states" are not organized anywhere...collected state strings: - // NOPROCESS,NONETWORK,BYTECOUNT,AUTH_FAILED + some parsing thing ( WAIT(?),AUTH,GET_CONFIG,ASSIGN_IP,CONNECTED,SIGINT ) - runOnUiThread(new Runnable() { - - @Override - public void run() { - if (eipStatus != null) { - boolean switchState = true; - String statusMessage = ""; - String prefix = getString(localizedResId); - if (state.equals("CONNECTED")){ - statusMessage = "Connection Secure"; - mEipStartPending = false; - } else if (state.equals("BYTECOUNT")) { - statusMessage = logmessage; - } else if (state.equals("NOPROCESS") || state.equals("EXITING")) { - statusMessage = "Not running! Connection not secure!"; - switchState = false; - } else { - statusMessage = prefix + logmessage; - } - - eipSwitch.setChecked(switchState); - eipStatus.setText(statusMessage); - } - } - }); - } - - /** - * Inner class for handling messages related to EIP status and control requests - * - * @author Sean Leonard - */ - protected class EIPReceiver extends ResultReceiver { - - Dashboard mDashboard; - - protected EIPReceiver(Handler handler){ - super(handler); - } - - public void setReceiver(Dashboard receiver) { - mDashboard = receiver; - } - - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - super.onReceiveResult(resultCode, resultData); - - String request = resultData.getString(ConfigHelper.REQUEST_TAG); - boolean checked = false; - - if (request == EIP.ACTION_IS_EIP_RUNNING) { - switch (resultCode){ - case RESULT_OK: - checked = true; - break; - case RESULT_CANCELED: - checked = false; - break; - } - } else if (request == EIP.ACTION_START_EIP) { - switch (resultCode){ - case RESULT_OK: - checked = true; - break; - case RESULT_CANCELED: - checked = false; - break; - } - } else if (request == EIP.ACTION_STOP_EIP) { - switch (resultCode){ - case RESULT_OK: - checked = false; - break; - case RESULT_CANCELED: - checked = true; - break; - } - } else if (request == EIP.EIP_NOTIFICATION) { - switch (resultCode){ - case RESULT_OK: - checked = true; - break; - case RESULT_CANCELED: - checked = false; - break; - } - } - - eipSwitch.setChecked(checked); - } - } } diff --git a/src/se/leap/leapclient/EipServiceFragment.java b/src/se/leap/leapclient/EipServiceFragment.java new file mode 100644 index 00000000..485a06af --- /dev/null +++ b/src/se/leap/leapclient/EipServiceFragment.java @@ -0,0 +1,234 @@ +package se.leap.leapclient; + +import se.leap.openvpn.LogWindow; +import se.leap.openvpn.OpenVPN; +import se.leap.openvpn.OpenVPN.StateListener; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Fragment; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.ResultReceiver; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.CompoundButton; +import android.widget.RelativeLayout; +import android.widget.Switch; +import android.widget.TextView; + +public class EipServiceFragment extends Fragment implements StateListener, OnClickListener, OnCheckedChangeListener { + + private View eipFragment; + private Switch eipSwitch; + private View eipDetail; + private TextView eipStatus; + + private boolean eipAutoSwitched = false; + + private boolean mEipStartPending = false; + + private EIPReceiver mEIPReceiver; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + eipFragment = inflater.inflate(R.layout.eip_service_fragment, container, false); + + eipDetail = ((RelativeLayout) eipFragment.findViewById(R.id.eipDetail)); + eipDetail.setVisibility(View.VISIBLE); + + View eipSettings = eipFragment.findViewById(R.id.eipSettings); + eipSettings.setVisibility(View.GONE); // FIXME too! + + eipStatus = (TextView) eipFragment.findViewById(R.id.eipStatus); + eipStatus.setOnClickListener(this); + + eipSwitch = (Switch) eipFragment.findViewById(R.id.eipSwitch); + eipSwitch.setOnCheckedChangeListener(this); + + return eipFragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mEIPReceiver = new EIPReceiver(new Handler()); + } + + @Override + public void onResume() { + super.onResume(); + + OpenVPN.addStateListener(this); + } + + @Override + public void onPause() { + super.onPause(); + + OpenVPN.removeStateListener(this); + } + + @Override + public void onClick(View buttonView) { + if (buttonView.equals(eipStatus)) + showEIPLog(); + } + + /** + * Launches the se.leap.openvpn.LogWindow Activity showing detailed OpenVPN log + */ + public void showEIPLog(){ + Intent intent = new Intent(getActivity().getBaseContext(),LogWindow.class); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + startActivity(intent); + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (buttonView.equals(eipSwitch) && !eipAutoSwitched){ + if (isChecked){ + mEipStartPending = true; + eipCommand(EIP.ACTION_START_EIP); + } else { + if (mEipStartPending){ + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity()); + alertBuilder.setTitle(getResources().getString(R.string.eip_cancel_connect_title)); + alertBuilder + .setMessage(getResources().getString(R.string.eip_cancel_connect_text)) + .setPositiveButton(getResources().getString(R.string.eip_cancel_connect_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + eipCommand(EIP.ACTION_STOP_EIP); + } + }) + .setNegativeButton(getResources().getString(R.string.eip_cancel_connect_false), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + eipAutoSwitched = true; + eipSwitch.setChecked(true); + eipAutoSwitched = false; + } + }) + .show(); + } else { + eipCommand(EIP.ACTION_STOP_EIP); + } + } + } + } + + /** + * Send a command to EIP + * + * @param action A valid String constant from EIP class representing an Intent + * filter for the EIP class + */ + private void eipCommand(String action){ + // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? + Intent vpnIntent = new Intent(action); + vpnIntent.putExtra(ConfigHelper.RECEIVER_TAG, mEIPReceiver); + getActivity().startService(vpnIntent); + } + + @Override + public void updateState(final String state, final String logmessage, final int localizedResId) { + // Note: "states" are not organized anywhere...collected state strings: + // NOPROCESS,NONETWORK,BYTECOUNT,AUTH_FAILED + some parsing thing ( WAIT(?),AUTH,GET_CONFIG,ASSIGN_IP,CONNECTED,SIGINT ) + getActivity().runOnUiThread(new Runnable() { + + @Override + public void run() { + if (eipStatus != null) { + boolean switchState = true; + String statusMessage = ""; + String prefix = getString(localizedResId); + if (state.equals("CONNECTED")){ + statusMessage = "Connection Secure"; + mEipStartPending = false; + } else if (state.equals("BYTECOUNT")) { + statusMessage = logmessage; + } else if (state.equals("NOPROCESS") || state.equals("EXITING")) { + statusMessage = "Not running! Connection not secure!"; + switchState = false; + } else { + statusMessage = prefix + logmessage; + } + + eipAutoSwitched = true; + eipSwitch.setChecked(switchState); + eipAutoSwitched = false; + eipStatus.setText(statusMessage); + } + } + }); + } + + /** + * Inner class for handling messages related to EIP status and control requests + * + * @author Sean Leonard + */ + protected class EIPReceiver extends ResultReceiver { + + protected EIPReceiver(Handler handler){ + super(handler); + } + + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + super.onReceiveResult(resultCode, resultData); + + String request = resultData.getString(ConfigHelper.REQUEST_TAG); + boolean checked = false; + + if (request == EIP.ACTION_IS_EIP_RUNNING) { + switch (resultCode){ + case Activity.RESULT_OK: + checked = true; + break; + case Activity.RESULT_CANCELED: + checked = false; + break; + } + } else if (request == EIP.ACTION_START_EIP) { + switch (resultCode){ + case Activity.RESULT_OK: + checked = true; + break; + case Activity.RESULT_CANCELED: + checked = false; + break; + } + } else if (request == EIP.ACTION_STOP_EIP) { + switch (resultCode){ + case Activity.RESULT_OK: + checked = false; + break; + case Activity.RESULT_CANCELED: + checked = true; + break; + } + } else if (request == EIP.EIP_NOTIFICATION) { + switch (resultCode){ + case Activity.RESULT_OK: + checked = true; + break; + case Activity.RESULT_CANCELED: + checked = false; + break; + } + } + + eipAutoSwitched = true; + eipSwitch.setChecked(checked); + eipAutoSwitched = false; + } + } +} -- cgit v1.2.3 From b19dc954b381c1e266395fdc1f19a1246096d4ab Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 21:57:43 -0600 Subject: Add a progress bar while VPN connection is being established --- res/layout/eip_service_fragment.xml | 11 +++++++++++ res/values/strings.xml | 1 + src/se/leap/leapclient/EipServiceFragment.java | 23 ++++++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/res/layout/eip_service_fragment.xml b/res/layout/eip_service_fragment.xml index 8f7c1d22..885c78a3 100644 --- a/res/layout/eip_service_fragment.xml +++ b/res/layout/eip_service_fragment.xml @@ -36,6 +36,17 @@ android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:layout_marginRight="10dp" /> + + Didn\'t logged out. Your own cert has been correctly downloaded. Your own cert has incorrectly been downloaded. + Initiating connection Cancel connection? There is a connection attempt in progress. Do you wish to cancel it? Yes diff --git a/src/se/leap/leapclient/EipServiceFragment.java b/src/se/leap/leapclient/EipServiceFragment.java index 485a06af..51284bc0 100644 --- a/src/se/leap/leapclient/EipServiceFragment.java +++ b/src/se/leap/leapclient/EipServiceFragment.java @@ -23,6 +23,8 @@ import android.widget.TextView; public class EipServiceFragment extends Fragment implements StateListener, OnClickListener, OnCheckedChangeListener { + private static final String IS_EIP_PENDING = "is_eip_pending"; + private View eipFragment; private Switch eipSwitch; private View eipDetail; @@ -37,6 +39,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + eipFragment = inflater.inflate(R.layout.eip_service_fragment, container, false); eipDetail = ((RelativeLayout) eipFragment.findViewById(R.id.eipDetail)); @@ -44,6 +47,9 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli View eipSettings = eipFragment.findViewById(R.id.eipSettings); eipSettings.setVisibility(View.GONE); // FIXME too! + + if (mEipStartPending) + eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); eipStatus = (TextView) eipFragment.findViewById(R.id.eipStatus); eipStatus.setOnClickListener(this); @@ -59,6 +65,9 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli super.onCreate(savedInstanceState); mEIPReceiver = new EIPReceiver(new Handler()); + + if (savedInstanceState != null) + mEipStartPending = savedInstanceState.getBoolean(IS_EIP_PENDING); } @Override @@ -75,6 +84,12 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli OpenVPN.removeStateListener(this); } + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(IS_EIP_PENDING, mEipStartPending); + } + @Override public void onClick(View buttonView) { if (buttonView.equals(eipStatus)) @@ -95,6 +110,8 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli if (buttonView.equals(eipSwitch) && !eipAutoSwitched){ if (isChecked){ mEipStartPending = true; + eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); + ((TextView) eipFragment.findViewById(R.id.eipStatus)).setText(R.string.eip_status_start_pending); eipCommand(EIP.ACTION_START_EIP); } else { if (mEipStartPending){ @@ -151,11 +168,14 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli String prefix = getString(localizedResId); if (state.equals("CONNECTED")){ statusMessage = "Connection Secure"; + getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); mEipStartPending = false; } else if (state.equals("BYTECOUNT")) { statusMessage = logmessage; - } else if (state.equals("NOPROCESS") || state.equals("EXITING")) { + } else if ( (state.equals("NOPROCESS") && !mEipStartPending ) || state.equals("EXITING")) { statusMessage = "Not running! Connection not secure!"; + getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); + mEipStartPending = false; switchState = false; } else { statusMessage = prefix + logmessage; @@ -204,6 +224,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli break; case Activity.RESULT_CANCELED: checked = false; + eipFragment.findViewById(R.id.eipProgress).setVisibility(View.GONE); break; } } else if (request == EIP.ACTION_STOP_EIP) { -- cgit v1.2.3 From f0c42391501aa646c5d65df5e19dbbd36b19b970 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 19 Jul 2013 14:11:29 -0600 Subject: Add logic to only trigger EIP control events if switch changed by a touch event. Fixes VPN reconnection when framework rebuilds view, triggering onCheckedChangeListener --- src/se/leap/leapclient/EipServiceFragment.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/se/leap/leapclient/EipServiceFragment.java b/src/se/leap/leapclient/EipServiceFragment.java index 51284bc0..c18f83da 100644 --- a/src/se/leap/leapclient/EipServiceFragment.java +++ b/src/se/leap/leapclient/EipServiceFragment.java @@ -12,6 +12,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; @@ -30,7 +31,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli private View eipDetail; private TextView eipStatus; - private boolean eipAutoSwitched = false; + private boolean eipAutoSwitched = true; private boolean mEipStartPending = false; @@ -55,6 +56,13 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli eipStatus.setOnClickListener(this); eipSwitch = (Switch) eipFragment.findViewById(R.id.eipSwitch); + eipSwitch.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + eipAutoSwitched = false; + return false; + } + }); eipSwitch.setOnCheckedChangeListener(this); return eipFragment; @@ -139,6 +147,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli } } } + eipAutoSwitched = true; } /** -- cgit v1.2.3