From d0ed8ee89e150cd063185d724a7a7e88e4d9dc25 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 13 Jun 2017 16:21:50 +0200 Subject: android: Add disconnect button to notification --- .../org/strongswan/android/logic/CharonVpnService.java | 5 +++++ .../main/res/drawable-hdpi/ic_notification_disconnect.png | Bin 0 -> 584 bytes .../main/res/drawable-mdpi/ic_notification_disconnect.png | Bin 0 -> 390 bytes .../res/drawable-xhdpi/ic_notification_disconnect.png | Bin 0 -> 794 bytes 4 files changed, 5 insertions(+) create mode 100644 src/frontends/android/app/src/main/res/drawable-hdpi/ic_notification_disconnect.png create mode 100644 src/frontends/android/app/src/main/res/drawable-mdpi/ic_notification_disconnect.png create mode 100644 src/frontends/android/app/src/main/res/drawable-xhdpi/ic_notification_disconnect.png diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java index 235681772..ecc69aed8 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java @@ -365,6 +365,11 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe builder.setContentTitle(getString(s)); if (!publicVersion) { + Intent intent = new Intent(getApplicationContext(), CharonVpnService.class); + intent.setAction(CharonVpnService.DISCONNECT_ACTION); + PendingIntent pending = PendingIntent.getService(getApplicationContext(), 0, intent, + PendingIntent.FLAG_ONE_SHOT); + builder.addAction(R.drawable.ic_notification_disconnect, getString(R.string.disconnect), pending); builder.setContentText(name); builder.setPublicVersion(buildNotification(true)); } diff --git a/src/frontends/android/app/src/main/res/drawable-hdpi/ic_notification_disconnect.png b/src/frontends/android/app/src/main/res/drawable-hdpi/ic_notification_disconnect.png new file mode 100644 index 000000000..1c94d195f Binary files /dev/null and b/src/frontends/android/app/src/main/res/drawable-hdpi/ic_notification_disconnect.png differ diff --git a/src/frontends/android/app/src/main/res/drawable-mdpi/ic_notification_disconnect.png b/src/frontends/android/app/src/main/res/drawable-mdpi/ic_notification_disconnect.png new file mode 100644 index 000000000..82c7277c0 Binary files /dev/null and b/src/frontends/android/app/src/main/res/drawable-mdpi/ic_notification_disconnect.png differ diff --git a/src/frontends/android/app/src/main/res/drawable-xhdpi/ic_notification_disconnect.png b/src/frontends/android/app/src/main/res/drawable-xhdpi/ic_notification_disconnect.png new file mode 100644 index 000000000..6dc5e5112 Binary files /dev/null and b/src/frontends/android/app/src/main/res/drawable-xhdpi/ic_notification_disconnect.png differ -- cgit v1.2.3 From 1265b353d4634892c9c97da19f2f197466891ba6 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 23 Jun 2017 10:35:08 +0200 Subject: android: Allow disconnecting via MainActivity but display a confirmation dialog --- .../strongswan/android/logic/CharonVpnService.java | 8 ++-- .../org/strongswan/android/ui/MainActivity.java | 49 +++++++++++++++++++++- .../android/app/src/main/res/values-de/strings.xml | 2 + .../android/app/src/main/res/values-pl/strings.xml | 2 + .../android/app/src/main/res/values-ru/strings.xml | 2 + .../android/app/src/main/res/values-ua/strings.xml | 2 + .../app/src/main/res/values-zh-rCN/strings.xml | 2 + .../app/src/main/res/values-zh-rTW/strings.xml | 2 + .../android/app/src/main/res/values/strings.xml | 2 + 9 files changed, 65 insertions(+), 6 deletions(-) diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java index ecc69aed8..cfed2e384 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/CharonVpnService.java @@ -365,10 +365,10 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe builder.setContentTitle(getString(s)); if (!publicVersion) { - Intent intent = new Intent(getApplicationContext(), CharonVpnService.class); - intent.setAction(CharonVpnService.DISCONNECT_ACTION); - PendingIntent pending = PendingIntent.getService(getApplicationContext(), 0, intent, - PendingIntent.FLAG_ONE_SHOT); + Intent intent = new Intent(getApplicationContext(), MainActivity.class); + intent.setAction(MainActivity.DISCONNECT); + PendingIntent pending = PendingIntent.getActivity(getApplicationContext(), 0, intent, + PendingIntent.FLAG_UPDATE_CURRENT); builder.addAction(R.drawable.ic_notification_disconnect, getString(R.string.disconnect), pending); builder.setContentText(name); builder.setPublicVersion(buildNotification(true)); diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/MainActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/MainActivity.java index 5ba1061c2..76aef7258 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/MainActivity.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/MainActivity.java @@ -2,7 +2,7 @@ * Copyright (C) 2012-2017 Tobias Brunner * Copyright (C) 2012 Giuliano Grassi * Copyright (C) 2012 Ralf Sager - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -58,6 +58,7 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec { public static final String CONTACT_EMAIL = "android@strongswan.org"; public static final String START_PROFILE = "org.strongswan.android.action.START_PROFILE"; + public static final String DISCONNECT = "org.strongswan.android.action.DISCONNECT"; public static final String EXTRA_VPN_PROFILE_ID = "org.strongswan.android.VPN_PROFILE_ID"; /** * Use "bring your own device" (BYOD) features @@ -67,6 +68,7 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec private static final String PROFILE_NAME = "org.strongswan.android.MainActivity.PROFILE_NAME"; private static final String PROFILE_REQUIRES_PASSWORD = "org.strongswan.android.MainActivity.REQUIRES_PASSWORD"; private static final String PROFILE_RECONNECT = "org.strongswan.android.MainActivity.RECONNECT"; + private static final String PROFILE_DISCONNECT = "org.strongswan.android.MainActivity.DISCONNECT"; private static final String DIALOG_TAG = "Dialog"; private Bundle mProfileInfo; @@ -88,6 +90,10 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec { startVpnProfile(getIntent()); } + else if (DISCONNECT.equals(getIntent().getAction())) + { + disconnect(); + } } }; @@ -132,6 +138,10 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec { startVpnProfile(intent); } + else if (DISCONNECT.equals(intent.getAction())) + { + disconnect(); + } } @Override @@ -303,6 +313,25 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec } } + /** + * Disconnect the current connection, if any (silently ignored if there is no connection). + */ + private void disconnect() + { + removeFragmentByTag(DIALOG_TAG); + + if (mService != null && (mService.getState() == State.CONNECTED || mService.getState() == State.CONNECTING)) + { + Bundle args = new Bundle(); + args.putBoolean(PROFILE_DISCONNECT, true); + + ConfirmationDialog dialog = new ConfirmationDialog(); + dialog.setArguments(args); + dialog.show(this.getSupportFragmentManager(), DIALOG_TAG); + return; + } + } + /** * Class that loads the cached CA certificates. */ @@ -364,6 +393,12 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec message = R.string.vpn_profile_connected; button = R.string.reconnect; } + else if (profileInfo.getBoolean(PROFILE_DISCONNECT)) + { + title = R.string.disconnect_question; + message = R.string.disconnect_active_connection; + button = R.string.disconnect; + } return new AlertDialog.Builder(getActivity()) .setIcon(icon) @@ -375,7 +410,17 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec public void onClick(DialogInterface dialog, int whichButton) { MainActivity activity = (MainActivity)getActivity(); - activity.startVpnProfile(profileInfo); + if (profileInfo.getBoolean(PROFILE_DISCONNECT)) + { + if (activity.mService != null) + { + activity.mService.disconnect(); + } + } + else + { + activity.startVpnProfile(profileInfo); + } } }) .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() diff --git a/src/frontends/android/app/src/main/res/values-de/strings.xml b/src/frontends/android/app/src/main/res/values-de/strings.xml index 34fe84609..bc6927d51 100644 --- a/src/frontends/android/app/src/main/res/values-de/strings.xml +++ b/src/frontends/android/app/src/main/res/values-de/strings.xml @@ -166,6 +166,8 @@ Neu verbinden Verbinde %1$s? Dies ersetzt die aktuelle VPN Verbindung! + VPN Verbindung trennen? + Dies trennt die aktuelle VPN Verbindung! Verbinden diff --git a/src/frontends/android/app/src/main/res/values-pl/strings.xml b/src/frontends/android/app/src/main/res/values-pl/strings.xml index a87381aa1..424837adf 100644 --- a/src/frontends/android/app/src/main/res/values-pl/strings.xml +++ b/src/frontends/android/app/src/main/res/values-pl/strings.xml @@ -166,6 +166,8 @@ Połączyć ponownie Połącz %1$s? To zastąpi aktywne połączenie VPN! + Disconnect VPN? + This will disconnect the active VPN connection! Połącz diff --git a/src/frontends/android/app/src/main/res/values-ru/strings.xml b/src/frontends/android/app/src/main/res/values-ru/strings.xml index 0ce54e56e..a53772014 100644 --- a/src/frontends/android/app/src/main/res/values-ru/strings.xml +++ b/src/frontends/android/app/src/main/res/values-ru/strings.xml @@ -163,6 +163,8 @@ Переподключить Подключить %1$s? Это заменит ваше текущее VPN соединение! + Disconnect VPN? + This will disconnect the active VPN connection! Соединить diff --git a/src/frontends/android/app/src/main/res/values-ua/strings.xml b/src/frontends/android/app/src/main/res/values-ua/strings.xml index 5b769b787..4d3600952 100644 --- a/src/frontends/android/app/src/main/res/values-ua/strings.xml +++ b/src/frontends/android/app/src/main/res/values-ua/strings.xml @@ -164,6 +164,8 @@ Перепідключитися Підключити %1$s? Ця дія замінить ваше поточне VPN з\'єднання! + Disconnect VPN? + This will disconnect the active VPN connection! Підключити diff --git a/src/frontends/android/app/src/main/res/values-zh-rCN/strings.xml b/src/frontends/android/app/src/main/res/values-zh-rCN/strings.xml index 4202c5f84..606bd2783 100644 --- a/src/frontends/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/frontends/android/app/src/main/res/values-zh-rCN/strings.xml @@ -163,6 +163,8 @@ 重连 是否连接%1$s? 这将覆盖您当前活跃的VPN连接! + Disconnect VPN? + This will disconnect the active VPN connection! 连接 diff --git a/src/frontends/android/app/src/main/res/values-zh-rTW/strings.xml b/src/frontends/android/app/src/main/res/values-zh-rTW/strings.xml index 6c0e104b5..52f21f8da 100644 --- a/src/frontends/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/frontends/android/app/src/main/res/values-zh-rTW/strings.xml @@ -163,6 +163,8 @@ 重新連線 是否連線%1$s? 這將會覆蓋您當前運作的VPN連線! + Disconnect VPN? + This will disconnect the active VPN connection! 連線 diff --git a/src/frontends/android/app/src/main/res/values/strings.xml b/src/frontends/android/app/src/main/res/values/strings.xml index f99f7dea5..4ee6be390 100644 --- a/src/frontends/android/app/src/main/res/values/strings.xml +++ b/src/frontends/android/app/src/main/res/values/strings.xml @@ -166,6 +166,8 @@ Reconnect Connect %1$s? This will replace your active VPN connection! + Disconnect VPN? + This will disconnect the active VPN connection! Connect -- cgit v1.2.3 From 6333a756eee462a4ae071b24fe3af218493cf9c5 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 30 Jun 2017 09:46:56 +0200 Subject: android: Close activity when dialog is canceled if it was not visible before onPause/onResume() won't work because onPause() is called right before onNewIntent(). --- .../org/strongswan/android/ui/MainActivity.java | 50 ++++++++++++++++++---- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/MainActivity.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/MainActivity.java index 76aef7258..efdeddd48 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/MainActivity.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/MainActivity.java @@ -69,8 +69,10 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec private static final String PROFILE_REQUIRES_PASSWORD = "org.strongswan.android.MainActivity.REQUIRES_PASSWORD"; private static final String PROFILE_RECONNECT = "org.strongswan.android.MainActivity.RECONNECT"; private static final String PROFILE_DISCONNECT = "org.strongswan.android.MainActivity.DISCONNECT"; + private static final String PROFILE_FOREGROUND = "org.strongswan.android.MainActivity.PROFILE_FOREGROUND"; private static final String DIALOG_TAG = "Dialog"; + private boolean mIsVisible; private Bundle mProfileInfo; private VpnStateService mService; private final ServiceConnection mServiceConnection = new ServiceConnection() @@ -88,11 +90,11 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec if (START_PROFILE.equals(getIntent().getAction())) { - startVpnProfile(getIntent()); + startVpnProfile(getIntent(), false); } else if (DISCONNECT.equals(getIntent().getAction())) { - disconnect(); + disconnect(false); } } }; @@ -126,6 +128,20 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec } } + @Override + protected void onStart() + { + super.onStart(); + mIsVisible = true; + } + + @Override + protected void onStop() + { + super.onStop(); + mIsVisible = false; + } + /** * Due to launchMode=singleTop this is called if the Activity already exists */ @@ -136,11 +152,11 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec if (START_PROFILE.equals(intent.getAction())) { - startVpnProfile(intent); + startVpnProfile(intent, mIsVisible); } else if (DISCONNECT.equals(intent.getAction())) { - disconnect(); + disconnect(mIsVisible); } } @@ -245,6 +261,17 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec @Override public void onVpnProfileSelected(VpnProfile profile) + { + startVpnProfile(profile, true); + } + + /** + * Start the given VPN profile + * + * @param profile VPN profile + * @param foreground whether this was initiated when the activity was visible + */ + public void startVpnProfile(VpnProfile profile, boolean foreground) { Bundle profileInfo = new Bundle(); profileInfo.putLong(VpnProfileDataSource.KEY_ID, profile.getId()); @@ -258,6 +285,7 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec if (mService != null && (mService.getState() == State.CONNECTED || mService.getState() == State.CONNECTING)) { profileInfo.putBoolean(PROFILE_RECONNECT, mService.getProfile().getId() == profile.getId()); + profileInfo.putBoolean(PROFILE_FOREGROUND, foreground); ConfirmationDialog dialog = new ConfirmationDialog(); dialog.setArguments(profileInfo); @@ -290,8 +318,9 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec * if the profile doesn't exist. * * @param intent Intent that caused us to start this + * @param foreground whether this was initiated when the activity was visible */ - private void startVpnProfile(Intent intent) + private void startVpnProfile(Intent intent, boolean foreground) { long profileId = intent.getLongExtra(EXTRA_VPN_PROFILE_ID, 0); if (profileId <= 0) @@ -305,7 +334,7 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec if (profile != null) { - onVpnProfileSelected(profile); + startVpnProfile(profile, foreground); } else { @@ -316,7 +345,7 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec /** * Disconnect the current connection, if any (silently ignored if there is no connection). */ - private void disconnect() + private void disconnect(boolean foreground) { removeFragmentByTag(DIALOG_TAG); @@ -324,11 +353,11 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec { Bundle args = new Bundle(); args.putBoolean(PROFILE_DISCONNECT, true); + args.putBoolean(PROFILE_FOREGROUND, foreground); ConfirmationDialog dialog = new ConfirmationDialog(); dialog.setArguments(args); dialog.show(this.getSupportFragmentManager(), DIALOG_TAG); - return; } } @@ -429,6 +458,11 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec public void onClick(DialogInterface dialog, int which) { dismiss(); + if (!profileInfo.getBoolean(PROFILE_FOREGROUND)) + { /* if the app was not in the foreground before this action was triggered + * externally, we just close the activity if canceled */ + getActivity().finish(); + } } }).create(); } -- cgit v1.2.3