From d0ed8ee89e150cd063185d724a7a7e88e4d9dc25 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 13 Jun 2017 16:21:50 +0200 Subject: [PATCH 1/3] android: Add disconnect button to notification --- .../android/logic/CharonVpnService.java | 5 +++++ .../drawable-hdpi/ic_notification_disconnect.png | Bin 0 -> 584 bytes .../drawable-mdpi/ic_notification_disconnect.png | Bin 0 -> 390 bytes .../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 235681772e..ecc69aed84 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 0000000000000000000000000000000000000000..1c94d195fe1b7532ca3688a915684c94f42e3707 GIT binary patch literal 584 zcmV-O0=NB%P)Vuc3K0vxAp`;ml2*xvlp*zQ z&cFya!*1MpsErp6i#qr0*|Yb~TqBWFoZ^V#d0rGq134hiuk3U5kRoD06&L~=!1ewH z`@9AQKxMDuK;8u2Jh^xU8m5ILfw9lczJM9f2YUQEDElZ`aZcwZWnohEWR=649V${d*o#t zy49^26AoEq@zkU@+40Wn!VHEg3POK=7}_>7{eVpfD_tU92j zfEU3jTau$DIKw8;q|O+7DTrb&%~|*TGgGq~Eb?`(AjUE==%;*M-*%sxvK^frGwkeR z2Qt~mXiT)638<+y>AtYRYNxgDf36L_c{%|i96sdPQmt)BoW&310>5Ss`rrN($Bthl W=Aly8Iu*tM0000w=*m7o5!B`WCDNnczOwyersacoysg3&EV@+OzW&j{aQ%;C)0Z@B`z#+bufxB{fq za2sO|_meUwWrPhu9wW?~Xmi&q8e=vIF-JRvJ9LpA1Yf*_Jixq-MjNeO)y+Ldg&~NK z`4LUmcOGTdu$vTj@{iNdj)$Y%LFh#7QLbW;ZS@IjpJ+2$}d0mb+7^A+)|Y#XRkRGo9+ zMM&{Vb-EB$sof^nTc6+lBjS5BpIsK8TeS&zs1V!$O`a20D_%M5)DwFzZomfMS|K<} zO1$ECB5twuae{V>fFD9{8;$R}@XN&sToBH0LL}@H{!7AlFi!9(;ru#D@yszR{3qfF zm=?}6q4&Ior|7bPf=vnaCEl=whFp^PeaM70@O>0qd6zPJ5PHvRIFA*sO6-XS)qZi1 zy-ZMiGqS2Fw(RAT2%hn?VP zVxDsi&uuXAVmp~~f==uMx;wGR8M=y7KS50qpYAu0 Date: Fri, 23 Jun 2017 10:35:08 +0200 Subject: [PATCH 2/3] android: Allow disconnecting via MainActivity but display a confirmation dialog --- .../android/logic/CharonVpnService.java | 8 +-- .../strongswan/android/ui/MainActivity.java | 49 ++++++++++++++++++- .../app/src/main/res/values-de/strings.xml | 2 + .../app/src/main/res/values-pl/strings.xml | 2 + .../app/src/main/res/values-ru/strings.xml | 2 + .../app/src/main/res/values-ua/strings.xml | 2 + .../src/main/res/values-zh-rCN/strings.xml | 2 + .../src/main/res/values-zh-rTW/strings.xml | 2 + .../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 ecc69aed84..cfed2e384e 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 5ba1061c2d..76aef72588 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 34fe846099..bc6927d512 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 a87381aa1e..424837adff 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 0ce54e56e2..a537720149 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 5b769b7870..4d3600952e 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 4202c5f846..606bd27837 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 6c0e104b53..52f21f8da1 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 f99f7dea5a..4ee6be3900 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 From 6333a756eee462a4ae071b24fe3af218493cf9c5 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 30 Jun 2017 09:46:56 +0200 Subject: [PATCH 3/3] 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(). --- .../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 76aef72588..efdeddd484 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(); }