]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
android: Request permission to display notifications on Android 13
authorTobias Brunner <tobias@strongswan.org>
Tue, 29 Aug 2023 15:45:32 +0000 (17:45 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 29 Aug 2023 16:03:30 +0000 (18:03 +0200)
Note that displaying the notification for the background service is
apparently not strictly necessary.  So it's fine if the user wants to
hide it.  That the service is running can still be seen in the task
manager (pull down the status drawer twice, there is a bullet with a number
at the bottom if the service is running).

Simply use the system dialog.  If the user denies it twice, it won't show
up again.  The explanation dialog would not show up the first time (i.e.
shouldShowRequestPermissionRationale() returns false), only once the user
denied the permission once.  Currently seems like a bit much work
as we don't need the user to allow notifications.

src/frontends/android/app/src/main/AndroidManifest.xml
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileControlActivity.java

index e6ed1df5e1d27d39c5983f21e7ac8a504d3ea173..89e3fb110ec06b4ddf8495ced8843a308c693af1 100644 (file)
@@ -22,6 +22,7 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
     <!-- necessary to allow users to select ex-/included apps and EAP-TNC -->
index 06821c6a60884efaeda77da39af351b2249d0e90..1913bbb5f3070c01a9806dce433297a6f82c31c5 100644 (file)
@@ -16,6 +16,7 @@
 
 package org.strongswan.android.ui;
 
+import android.Manifest;
 import android.app.Dialog;
 import android.app.Service;
 import android.content.ActivityNotFoundException;
@@ -25,6 +26,7 @@ import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.net.VpnService;
 import android.os.Build;
@@ -45,12 +47,14 @@ import org.strongswan.android.logic.VpnStateService;
 import org.strongswan.android.logic.VpnStateService.State;
 import org.strongswan.android.utils.Constants;
 
+import androidx.activity.result.ActivityResultCallback;
 import androidx.activity.result.ActivityResultLauncher;
 import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.annotation.NonNull;
 import androidx.appcompat.app.AlertDialog;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.app.AppCompatDialogFragment;
+import androidx.core.content.ContextCompat;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
 import androidx.fragment.app.FragmentTransaction;
@@ -107,11 +111,18 @@ public class VpnProfileControlActivity extends AppCompatActivity
                new ActivityResultContracts.StartActivityForResult(),
                result -> {
                        mWaitingForResult = false;
-                       if (mProfileInfo != null && mService != null)
+                       if (checkNotificationPermission())
                        {
-                               mService.connect(mProfileInfo, true);
+                               performConnect();
                        }
-                       finish();
+               }
+       );
+
+       private final ActivityResultLauncher<String> mRequestPermission = registerForActivityResult(
+               new ActivityResultContracts.RequestPermission(),
+               result -> {
+                       mWaitingForResult = false;
+                       performConnect();
                }
        );
 
@@ -219,22 +230,47 @@ public class VpnProfileControlActivity extends AppCompatActivity
                }
        }
 
+       /**
+        * Called to actually perform the connection and terminating the activity.
+        */
+       protected void performConnect()
+       {
+               if (mProfileInfo != null && mService != null)
+               {
+                       mService.connect(mProfileInfo, true);
+               }
+               finish();
+       }
+
        /**
         * Called once the VpnService has been prepared and permission has been granted
         * by the user.
         */
        protected void onVpnServicePrepared()
        {
-               if (checkPowerWhitelist())
+               if (checkPowerWhitelist() && checkNotificationPermission())
                {
-                       if (mService != null)
-                       {
-                               mService.connect(mProfileInfo, true);
-                       }
-                       finish();
+                       performConnect();
                }
        }
 
+       /**
+        * Check if we have permission to display notifications to the user, if necessary,
+        * ask the user to allow this.
+        * @return true if profile can be initiated immediately
+        */
+       private boolean checkNotificationPermission()
+       {
+               if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
+                       ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED)
+               {
+                       mWaitingForResult = true;
+                       mRequestPermission.launch(Manifest.permission.POST_NOTIFICATIONS);
+                       return false;
+               }
+               return true;
+       }
+
        /**
         * Check if we are on the system's power whitelist, if necessary, or ask the user
         * to add us.