]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
android: Ask user to add our app to the device's power whitelist
authorTobias Brunner <tobias@strongswan.org>
Fri, 8 May 2020 10:17:52 +0000 (12:17 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 2 Jun 2020 12:07:06 +0000 (14:07 +0200)
This is necessary so we can actually schedule events accurately in Doze
mode. Otherwise, we'd only get woken in intervals of several minutes (up to
15 according to the docs) after about an hour.

src/frontends/android/app/src/main/AndroidManifest.xml
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileControlActivity.java
src/frontends/android/app/src/main/res/values-de/strings.xml
src/frontends/android/app/src/main/res/values-pl/strings.xml
src/frontends/android/app/src/main/res/values-ru/strings.xml
src/frontends/android/app/src/main/res/values-ua/strings.xml
src/frontends/android/app/src/main/res/values-zh-rCN/strings.xml
src/frontends/android/app/src/main/res/values-zh-rTW/strings.xml
src/frontends/android/app/src/main/res/values/strings.xml

index 2b2ddfcdd77fd19f203123ec76ac88ecb31718bc..6c61e06f17d2a1e10260ba95acd9a1418c6da96e 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-    Copyright (C) 2012-2018 Tobias Brunner
+    Copyright (C) 2012-2020 Tobias Brunner
     Copyright (C) 2012 Giuliano Grassi
     Copyright (C) 2012 Ralf Sager
     HSR Hochschule fuer Technik Rapperswil
@@ -22,6 +22,7 @@
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
 
     <application
         android:name=".logic.StrongSwanApplication"
index 813afbb94195ad0cdba7d4b365df6a814117e7f3..896c9de94f316c2cf45fd983b47de3b1d00b5a1b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2018 Tobias Brunner
+ * Copyright (C) 2012-2020 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -19,12 +19,17 @@ import android.app.Dialog;
 import android.app.Service;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.net.Uri;
 import android.net.VpnService;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.PowerManager;
+import android.provider.Settings;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.EditText;
@@ -37,6 +42,7 @@ import org.strongswan.android.data.VpnType.VpnTypeFeature;
 import org.strongswan.android.logic.VpnStateService;
 import org.strongswan.android.logic.VpnStateService.State;
 
+import androidx.annotation.NonNull;
 import androidx.appcompat.app.AlertDialog;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.app.AppCompatDialogFragment;
@@ -51,6 +57,7 @@ public class VpnProfileControlActivity extends AppCompatActivity
        public static final String EXTRA_VPN_PROFILE_ID = "org.strongswan.android.VPN_PROFILE_ID";
 
        private static final int PREPARE_VPN_SERVICE = 0;
+       private static final int ADD_TO_POWER_WHITELIST = 1;
        private static final String WAITING_FOR_RESULT = "WAITING_FOR_RESULT";
        private static final String PROFILE_NAME = "PROFILE_NAME";
        private static final String PROFILE_REQUIRES_PASSWORD = "REQUIRES_PASSWORD";
@@ -181,6 +188,27 @@ public class VpnProfileControlActivity extends AppCompatActivity
                }
        }
 
+       /**
+        * Check if we are on the system's power whitelist, if necessary, or ask the user
+        * to add us.
+        * @return true if profile can be initiated immediately
+        */
+       private boolean checkPowerWhitelist()
+       {
+               if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
+               {
+                       PowerManager pm = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
+                       if (!pm.isIgnoringBatteryOptimizations(this.getPackageName()))
+                       {
+                               PowerWhitelistRequired whitelist = new PowerWhitelistRequired();
+                               mWaitingForResult = true;
+                               whitelist.show(getSupportFragmentManager(), DIALOG_TAG);
+                               return false;
+                       }
+               }
+               return true;
+       }
+
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data)
        {
@@ -190,11 +218,14 @@ public class VpnProfileControlActivity extends AppCompatActivity
                                mWaitingForResult = false;
                                if (resultCode == RESULT_OK && mProfileInfo != null)
                                {
-                                       if (mService != null)
+                                       if (checkPowerWhitelist())
                                        {
-                                               mService.connect(mProfileInfo, true);
+                                               if (mService != null)
+                                               {
+                                                       mService.connect(mProfileInfo, true);
+                                               }
+                                               finish();
                                        }
-                                       finish();
                                }
                                else
                                {       /* this happens if the always-on VPN feature is activated by a different app or the user declined */
@@ -207,6 +238,14 @@ public class VpnProfileControlActivity extends AppCompatActivity
                                        VpnNotSupportedError.showWithMessage(this, R.string.vpn_not_supported_no_permission);
                                }
                                break;
+                       case ADD_TO_POWER_WHITELIST:
+                               mWaitingForResult = false;
+                               if (mProfileInfo != null && mService != null)
+                               {
+                                       mService.connect(mProfileInfo, true);
+                               }
+                               finish();
+                               break;
                        default:
                                super.onActivityResult(requestCode, resultCode, data);
                }
@@ -531,6 +570,32 @@ public class VpnProfileControlActivity extends AppCompatActivity
                }
        }
 
+       /**
+        * Class that displays a warning before asking the user to add the app to the
+        * device's power whitelist.
+        */
+       public static class PowerWhitelistRequired extends AppCompatDialogFragment
+       {
+               @Override
+               public Dialog onCreateDialog(Bundle savedInstanceState)
+               {
+                       return new AlertDialog.Builder(getActivity())
+                               .setTitle(R.string.power_whitelist_title)
+                               .setMessage(R.string.power_whitelist_text)
+                               .setPositiveButton(android.R.string.ok, (dialog, id) -> {
+                                       Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
+                                                                                          Uri.parse("package:" + getActivity().getPackageName()));
+                                       getActivity().startActivityForResult(intent, ADD_TO_POWER_WHITELIST);
+                               }).create();
+               }
+
+               @Override
+               public void onCancel(@NonNull DialogInterface dialog)
+               {
+                       getActivity().finish();
+               }
+       }
+
        /**
         * Class representing an error message which is displayed if VpnService is
         * not supported on the current device.
@@ -556,7 +621,6 @@ public class VpnProfileControlActivity extends AppCompatActivity
                        return new AlertDialog.Builder(getActivity())
                                .setTitle(R.string.vpn_not_supported_title)
                                .setMessage(messageId)
-                               .setCancelable(false)
                                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
                                {
                                        @Override
index fcd14ea247b2be5625919b050d63aaddb96dd75a..76652bc6318e4e009cd6b91142ce39d06d49f852 100644 (file)
         <item quantity="other">Wiederholen in %1$d Sekunden</item>
     </plurals>
     <string name="cancel_retry">Wiederholen abbrechen</string>
+    <string name="power_whitelist_title">Akku-Optimierung deaktivieren</string>
+    <string name="power_whitelist_text">Bitte den nächsten Dialog bestätigen, um die App auf die weisse Liste für Akku-Optimierung zu setzen, so dass sie NAT keepalives und Rekeyings zeitlich korrekt planen kann, um konstant erreichbar zu bleiben während die VPN-Verbindung besteht.</string>
 
     <!-- Quick Settings tile -->
     <string name="tile_default">VPN umschalten</string>
index 6f4716ba84b202b19495b8288721bf31f4e127ce..2e1df077ee31baa9b17b367d69b482937a726e44 100644 (file)
         <item quantity="other">Retry in %1$d seconds</item>
     </plurals>
     <string name="cancel_retry">Cancel retry</string>
+    <string name="power_whitelist_title">Disable battery optimizations</string>
+    <string name="power_whitelist_text">Please confirm the next dialog to add the app to the device\'s power whitelist so it can ignore battery optimizations and schedule NAT keep-alives and rekeyings accurately in order to constantly keep reachable while the VPN is established.</string>
 
     <!-- Quick Settings tile -->
     <string name="tile_default">Toggle VPN</string>
index 5def66df8b7534ab6f3d04fc167d4e65848d7801..23fa95d38371b4d0cab7542d13ec12338807d899 100644 (file)
         <item quantity="other">Retry in %1$d seconds</item>
     </plurals>
     <string name="cancel_retry">Cancel retry</string>
+    <string name="power_whitelist_title">Disable battery optimizations</string>
+    <string name="power_whitelist_text">Please confirm the next dialog to add the app to the device\'s power whitelist so it can ignore battery optimizations and schedule NAT keep-alives and rekeyings accurately in order to constantly keep reachable while the VPN is established.</string>
 
     <!-- Quick Settings tile -->
     <string name="tile_default">Toggle VPN</string>
index 4920aa2385204565d3a378026a42e197dc2cc288..b4937364e15ef72134c19db953ed149a9864cdfc 100644 (file)
         <item quantity="other">Retry in %1$d seconds</item>
     </plurals>
     <string name="cancel_retry">Cancel retry</string>
+    <string name="power_whitelist_title">Disable battery optimizations</string>
+    <string name="power_whitelist_text">Please confirm the next dialog to add the app to the device\'s power whitelist so it can ignore battery optimizations and schedule NAT keep-alives and rekeyings accurately in order to constantly keep reachable while the VPN is established.</string>
 
     <!-- Quick Settings tile -->
     <string name="tile_default">Toggle VPN</string>
index 3408f5f55f479736d415fdc0cddae045eb92d516..c1dbefb665b1506d5e81159540e31fbf8b6f4f6d 100644 (file)
         <item quantity="other">Retry in %1$d seconds</item>
     </plurals>
     <string name="cancel_retry">Cancel retry</string>
+    <string name="power_whitelist_title">Disable battery optimizations</string>
+    <string name="power_whitelist_text">Please confirm the next dialog to add the app to the device\'s power whitelist so it can ignore battery optimizations and schedule NAT keep-alives and rekeyings accurately in order to constantly keep reachable while the VPN is established.</string>
 
     <!-- Quick Settings tile -->
     <string name="tile_default">Toggle VPN</string>
index e3d7f0361686cd96cea48a5525b0a9f3669b0a0d..13e75a43b4364413492617a09955661ea0e2adc9 100644 (file)
         <item quantity="other">Retry in %1$d seconds</item>
     </plurals>
     <string name="cancel_retry">Cancel retry</string>
+    <string name="power_whitelist_title">Disable battery optimizations</string>
+    <string name="power_whitelist_text">Please confirm the next dialog to add the app to the device\'s power whitelist so it can ignore battery optimizations and schedule NAT keep-alives and rekeyings accurately in order to constantly keep reachable while the VPN is established.</string>
 
     <!-- Quick Settings tile -->
     <string name="tile_default">Toggle VPN</string>
index 4d9fd879f21faae169ec339f50e5b8c2a6b06bc0..fb74d3f8332300dafa59d8ad2c7258f96b1d82a2 100644 (file)
         <item quantity="other">Retry in %1$d seconds</item>
     </plurals>
     <string name="cancel_retry">Cancel retry</string>
+    <string name="power_whitelist_title">Disable battery optimizations</string>
+    <string name="power_whitelist_text">Please confirm the next dialog to add the app to the device\'s power whitelist so it can ignore battery optimizations and schedule NAT keep-alives and rekeyings accurately in order to constantly keep reachable while the VPN is established.</string>
 
     <!-- Quick Settings tile -->
     <string name="tile_default">Toggle VPN</string>