From 055986820eaa59007173455d0787921898320491 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Wed, 11 Oct 2023 12:31:10 +0200 Subject: Update NDK version --- main/src/main/cpp/ovpnutil/osslutil.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'main/src') diff --git a/main/src/main/cpp/ovpnutil/osslutil.cpp b/main/src/main/cpp/ovpnutil/osslutil.cpp index 6a33338e..1921223c 100644 --- a/main/src/main/cpp/ovpnutil/osslutil.cpp +++ b/main/src/main/cpp/ovpnutil/osslutil.cpp @@ -113,9 +113,12 @@ extern "C" jbyteArray Java_de_blinkt_openvpn_core_NativeUtils_rsapss(JNIEnv *env if (!EVP_DigestFinal_ex(ctx, H, nullptr)) goto err; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" /* Generate dbMask in place then perform XOR on it */ if (PKCS1_MGF1(EM, maskedDBLen, H, hLen, mgf1Hash)) goto err; +#pragma clang diagnostic pop p = EM; -- cgit v1.2.3 From 33d26ab1a6ea1f9bddf5e55a5cc6dad54165a94e Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Fri, 10 Nov 2023 15:47:27 +0100 Subject: Update OpenSSL, OpenVPN and OpenVPN3 to latest versions --- main/src/main/cpp/openssl | 2 +- main/src/main/cpp/openvpn | 2 +- main/src/main/cpp/openvpn3 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'main/src') diff --git a/main/src/main/cpp/openssl b/main/src/main/cpp/openssl index bf2a6fac..c8a42c1d 160000 --- a/main/src/main/cpp/openssl +++ b/main/src/main/cpp/openssl @@ -1 +1 @@ -Subproject commit bf2a6facba08b980a00f2f2c4e46487471b17f63 +Subproject commit c8a42c1d6e25722adfa03f47f08b82733720512a diff --git a/main/src/main/cpp/openvpn b/main/src/main/cpp/openvpn index a80f21b1..eebb6934 160000 --- a/main/src/main/cpp/openvpn +++ b/main/src/main/cpp/openvpn @@ -1 +1 @@ -Subproject commit a80f21b133ebf10bc3c36577fedef024c6ed3035 +Subproject commit eebb69344ba57456ec7f2e6b0c692583f5f5e8ab diff --git a/main/src/main/cpp/openvpn3 b/main/src/main/cpp/openvpn3 index f1597101..697e4134 160000 --- a/main/src/main/cpp/openvpn3 +++ b/main/src/main/cpp/openvpn3 @@ -1 +1 @@ -Subproject commit f159710100e1442c7354b4f24cbfe742abc8c89b +Subproject commit 697e413435066fdf617cad1e0ba0f67144f2298e -- cgit v1.2.3 From 823cb52eff9934d36214af161759580bac589fdf Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 11 Nov 2023 17:02:22 +0100 Subject: Allow setting restart VPN on Boot setting via App restrictions --- main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java | 8 ++++++++ main/src/main/res/values/untranslatable.xml | 1 + main/src/main/res/xml/app_restrictions.xml | 5 +++++ 3 files changed, 14 insertions(+) (limited to 'main/src') diff --git a/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java b/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java index 53919216..48fbb2da 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java +++ b/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java @@ -147,6 +147,13 @@ public class AppRestrictions { editor.putBoolean("screenoff", pauseVPN); editor.apply(); } + if (restrictions.containsKey("restartvpnonboot")) + { + boolean restartVPNonBoot = restrictions.getBoolean("restartvpnonboot"); + SharedPreferences.Editor editor = defaultPrefs.edit(); + editor.putBoolean("restartvpnonboot", restartVPNonBoot); + editor.apply(); + } } private void importVPNProfiles(Context c, Bundle restrictions, Parcelable[] profileList) { @@ -155,6 +162,7 @@ public class AppRestrictions { String defaultprofile = restrictions.getString("defaultprofile", null); boolean defaultprofileProvisioned = false; + ProfileManager pm = ProfileManager.getInstance(c); for (Parcelable profile : profileList) { if (!(profile instanceof Bundle)) { diff --git a/main/src/main/res/values/untranslatable.xml b/main/src/main/res/values/untranslatable.xml index 6b3c1f70..edafd76e 100644 --- a/main/src/main/res/values/untranslatable.xml +++ b/main/src/main/res/values/untranslatable.xml @@ -85,6 +85,7 @@ Failed to negotiate cipher with server URL Pause VPN when screen is off and less than 64 kB transferred data in 60s + Enable the workaround to use an on boot receiver to start the VPN if the Always On VPN functionality is not available List of apps that are allowed to use the remote AIDL. If this list is in the restrictions, the app will not allowed any changes to the list by the user. Package names of allowed apps separated by comma, space or newlines Remote API access diff --git a/main/src/main/res/xml/app_restrictions.xml b/main/src/main/res/xml/app_restrictions.xml index b3258b50..81171d6f 100644 --- a/main/src/main/res/xml/app_restrictions.xml +++ b/main/src/main/res/xml/app_restrictions.xml @@ -72,6 +72,11 @@ android:key="screenoffpausevpn" android:restrictionType="bool" android:title="@string/restriction_pausevpn" /> + + Date: Fri, 24 Nov 2023 15:51:27 +0100 Subject: Add @StringRes annotations to VPNStatus log methods --- main/src/main/java/de/blinkt/openvpn/core/LogItem.java | 4 +++- main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java | 12 +++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'main/src') diff --git a/main/src/main/java/de/blinkt/openvpn/core/LogItem.java b/main/src/main/java/de/blinkt/openvpn/core/LogItem.java index 65714c43..3ec2e438 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/LogItem.java +++ b/main/src/main/java/de/blinkt/openvpn/core/LogItem.java @@ -15,6 +15,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; +import androidx.annotation.StringRes; + import java.io.ByteArrayInputStream; import java.io.UnsupportedEncodingException; import java.lang.reflect.Array; @@ -239,7 +241,7 @@ public class LogItem implements Parcelable { } }; - public LogItem(VpnStatus.LogLevel loglevel, int ressourceId, Object... args) { + public LogItem(VpnStatus.LogLevel loglevel, @StringRes int ressourceId, Object... args) { mRessourceId = ressourceId; mArgs = args; mLevel = loglevel; diff --git a/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java b/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java index d1814fc2..fb55cba3 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java +++ b/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java @@ -11,6 +11,8 @@ import android.os.Build; import android.os.HandlerThread; import android.os.Message; +import androidx.annotation.StringRes; + import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; @@ -408,11 +410,11 @@ public class VpnStatus { newLogItem(new LogItem(LogLevel.DEBUG, message)); } - public static void logInfo(int resourceId, Object... args) { + public static void logInfo(@StringRes int resourceId, Object... args) { newLogItem(new LogItem(LogLevel.INFO, resourceId, args)); } - public static void logDebug(int resourceId, Object... args) { + public static void logDebug(@StringRes int resourceId, Object... args) { newLogItem(new LogItem(LogLevel.DEBUG, resourceId, args)); } @@ -486,7 +488,7 @@ public class VpnStatus { } - public static void logWarning(int resourceId, Object... args) { + public static void logWarning(@StringRes int resourceId, Object... args) { newLogItem(new LogItem(LogLevel.WARNING, resourceId, args)); } @@ -495,11 +497,11 @@ public class VpnStatus { } - public static void logError(int resourceId) { + public static void logError(@StringRes int resourceId) { newLogItem(new LogItem(LogLevel.ERROR, resourceId)); } - public static void logError(int resourceId, Object... args) { + public static void logError(@StringRes int resourceId, Object... args) { newLogItem(new LogItem(LogLevel.ERROR, resourceId, args)); } -- cgit v1.2.3 From a9e47acac093af3c9031a381593bbe40e8162160 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Fri, 24 Nov 2023 15:52:52 +0100 Subject: Allow OpenVPNService to request VPN permission if it is missing With other services no longer being able to easily request permissions the service needs now its own way to request permissions. --- .../de/blinkt/openvpn/core/OpenVPNService.java | 40 +++++++++++++++++++--- .../de/blinkt/openvpn/core/StatusListener.java | 14 ++++---- main/src/main/res/values/strings.xml | 3 +- 3 files changed, 46 insertions(+), 11 deletions(-) (limited to 'main/src') diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index 0e8793e4..983b63f3 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -5,6 +5,7 @@ package de.blinkt.openvpn.core; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; import static de.blinkt.openvpn.core.NetworkSpace.IpAddress; @@ -14,8 +15,6 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.UiModeManager; -import android.app.job.JobInfo; -import android.app.job.JobScheduler; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -37,7 +36,6 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; -import android.os.PersistableBundle; import android.os.RemoteException; import android.system.OsConstants; import android.text.TextUtils; @@ -528,6 +526,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac return START_REDELIVER_INTENT; } + // Always show notification here to avoid problem with startForeground timeout VpnStatus.logInfo(R.string.building_configration); VpnStatus.updateStateString("VPN_GENERATE_CONFIG", "", R.string.building_configration, ConnectionStatus.LEVEL_START); @@ -596,6 +595,34 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac return mProfile; } + private boolean checkVPNPermission(VpnProfile startprofile) { + if (prepare(this) == null) + return true; + + NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + Notification.Builder nbuilder = new Notification.Builder(this); + nbuilder.setAutoCancel(true); + int icon = android.R.drawable.ic_dialog_info; + nbuilder.setSmallIcon(icon); + + Intent launchVPNIntent = new Intent(this, LaunchVPN.class); + launchVPNIntent.putExtra(LaunchVPN.EXTRA_KEY, startprofile.getUUIDString()); + launchVPNIntent.putExtra(LaunchVPN.EXTRA_START_REASON, "OpenService lacks permission"); + launchVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_HIDELOG, true); + launchVPNIntent.addFlags(FLAG_ACTIVITY_NEW_TASK); + launchVPNIntent.setAction(Intent.ACTION_MAIN); + + + showNotification(getString(R.string.permission_requested), + "", NOTIFICATION_CHANNEL_USERREQ_ID, 0, LEVEL_WAITING_FOR_USER_INPUT, launchVPNIntent); + + VpnStatus.updateStateString("USER_INPUT", "waiting for user input", R.string.permission_requested, LEVEL_WAITING_FOR_USER_INPUT, launchVPNIntent); + return false; + } + + + private void startOpenVPN(Intent intent, int startId) { VpnProfile vp = fetchVPNProfile(intent); if (vp == null) { @@ -603,6 +630,9 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac return; } + if (!checkVPNPermission(vp)) + return; + ProfileManager.setConnectedVpnProfile(this, mProfile); VpnStatus.setConnectedVPNProfile(mProfile.getUUIDString()); keepVPNAlive.scheduleKeepVPNAliveJobService(this, vp); @@ -1353,7 +1383,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } public void trigger_sso(String info) { - String channel = NOTIFICATION_CHANNEL_USERREQ_ID; String method = info.split(":", 2)[0]; NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); @@ -1414,12 +1443,15 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac // updateStateString trigger the notification of the VPN to be refreshed, save this intent // to have that notification also this intent to be set PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE); + VpnStatus.updateStateString("USER_INPUT", "waiting for user input", reason, LEVEL_WAITING_FOR_USER_INPUT, intent); + nbuilder.setContentIntent(pIntent); jbNotificationExtras(PRIORITY_MAX, nbuilder); lpNotificationExtras(nbuilder, Notification.CATEGORY_STATUS); + String channel = NOTIFICATION_CHANNEL_USERREQ_ID; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //noinspection NewApi nbuilder.setChannelId(channel); diff --git a/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java b/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java index 293a6fd4..7eea523a 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java +++ b/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java @@ -120,9 +120,10 @@ public class StatusListener implements VpnStatus.LogListener { }; private Context mContext; + private String pkgName = "(packageName not yet set)"; void init(Context c) { - + pkgName = c.getPackageName(); Intent intent = new Intent(c, OpenVPNStatusService.class); intent.setAction(OpenVPNService.START_SERVICE); mCacheDir = c.getCacheDir(); @@ -163,22 +164,23 @@ public class StatusListener implements VpnStatus.LogListener { @Override public void newLog(LogItem logItem) { + String tag = pkgName + "(OpenVPN)"; switch (logItem.getLogLevel()) { case INFO: - Log.i("OpenVPN", logItem.getString(mContext)); + Log.i(tag, logItem.getString(mContext)); break; case DEBUG: - Log.d("OpenVPN", logItem.getString(mContext)); + Log.d(tag, logItem.getString(mContext)); break; case ERROR: - Log.e("OpenVPN", logItem.getString(mContext)); + Log.e(tag, logItem.getString(mContext)); break; case VERBOSE: - Log.v("OpenVPN", logItem.getString(mContext)); + Log.v(tag, logItem.getString(mContext)); break; case WARNING: default: - Log.w("OpenVPN", logItem.getString(mContext)); + Log.w(tag, logItem.getString(mContext)); break; } diff --git a/main/src/main/res/values/strings.xml b/main/src/main/res/values/strings.xml index 575933ed..88f98a17 100755 --- a/main/src/main/res/values/strings.xml +++ b/main/src/main/res/values/strings.xml @@ -508,5 +508,6 @@ Try to encrypt profiles on storage (if supported by Android OS) Notification permission missing. This is used to display the status of the VPN and to notify about required user interaction like multi factor authorisation.\n\nClick this message to give the app notification permissions Username - + Permission to start a VPN connection is required + VPN Service is missing permission to connect a VPN. Requesting permission via notification. -- cgit v1.2.3 From 8da735fe0a854151d3d314567696cf0915265066 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 28 Nov 2023 13:30:17 +0100 Subject: Use OpenSSL 3.2.0 --- main/src/main/cpp/openssl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main/src') diff --git a/main/src/main/cpp/openssl b/main/src/main/cpp/openssl index c8a42c1d..479b1b83 160000 --- a/main/src/main/cpp/openssl +++ b/main/src/main/cpp/openssl @@ -1 +1 @@ -Subproject commit c8a42c1d6e25722adfa03f47f08b82733720512a +Subproject commit 479b1b83891105c382cacdf71aeb35c14e994219 -- cgit v1.2.3 From a85b59e84b34a87e94c862334c1def5606e44388 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 28 Nov 2023 13:36:46 +0100 Subject: Improve debug logging --- .../de/blinkt/openvpn/core/StatusListener.java | 28 ++++++++++------------ 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'main/src') diff --git a/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java b/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java index 7eea523a..f7aef095 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java +++ b/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java @@ -26,6 +26,7 @@ import java.io.DataInputStream; import java.io.File; import java.io.IOException; import java.util.List; +import java.util.Locale; /** * Created by arne on 09.11.16. @@ -165,23 +166,18 @@ public class StatusListener implements VpnStatus.LogListener { @Override public void newLog(LogItem logItem) { String tag = pkgName + "(OpenVPN)"; + long logAge = System.currentTimeMillis() - logItem.getLogtime(); + if (logAge > 5000) + { + tag += String.format(Locale.US, "[%ds ago]", logAge/1000 ); + } + switch (logItem.getLogLevel()) { - case INFO: - Log.i(tag, logItem.getString(mContext)); - break; - case DEBUG: - Log.d(tag, logItem.getString(mContext)); - break; - case ERROR: - Log.e(tag, logItem.getString(mContext)); - break; - case VERBOSE: - Log.v(tag, logItem.getString(mContext)); - break; - case WARNING: - default: - Log.w(tag, logItem.getString(mContext)); - break; + case INFO -> Log.i(tag, logItem.getString(mContext)); + case DEBUG -> Log.d(tag, logItem.getString(mContext)); + case ERROR -> Log.e(tag, logItem.getString(mContext)); + case VERBOSE -> Log.v(tag, logItem.getString(mContext)); + default -> Log.w(tag, logItem.getString(mContext)); } } -- cgit v1.2.3 From b4b37f1531447c3abf3ef6df25d833724402713f Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 30 Nov 2023 11:56:16 +0100 Subject: Clean up extra for VPN start intents and try to avoid replacing VPN on autostarts --- .../src/main/java/de/blinkt/openvpn/LaunchVPN.java | 6 ++- .../java/de/blinkt/openvpn/OnBootReceiver.java | 2 +- .../main/java/de/blinkt/openvpn/VpnProfile.java | 20 ++++---- .../blinkt/openvpn/activities/DisconnectVPN.java | 2 +- .../blinkt/openvpn/api/ExternalOpenVPNService.java | 8 +-- .../java/de/blinkt/openvpn/api/RemoteAction.java | 2 +- .../de/blinkt/openvpn/core/OpenVPNService.java | 58 +++++++++++++++------- .../de/blinkt/openvpn/core/VPNLaunchHelper.java | 4 +- .../java/de/blinkt/openvpn/core/keepVPNAlive.java | 2 +- .../java/de/blinkt/openvpn/OpenVPNTileService.java | 2 +- .../blinkt/openvpn/activities/CreateShortcuts.java | 4 +- .../de/blinkt/openvpn/fragments/LogFragment.java | 2 +- .../blinkt/openvpn/fragments/VPNProfileList.java | 5 +- 13 files changed, 71 insertions(+), 46 deletions(-) (limited to 'main/src') diff --git a/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java b/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java index 90ea053a..a4a4cc5f 100644 --- a/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java +++ b/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java @@ -5,6 +5,8 @@ package de.blinkt.openvpn; +import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_START_REASON; + import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; @@ -73,7 +75,7 @@ public class LaunchVPN extends Activity { public static final String EXTRA_KEY = "de.blinkt.openvpn.shortcutProfileUUID"; public static final String EXTRA_NAME = "de.blinkt.openvpn.shortcutProfileName"; public static final String EXTRA_HIDELOG = "de.blinkt.openvpn.showNoLogWindow"; - public static final String EXTRA_START_REASON = "de.blinkt.openvpn.start_reason"; + public static final String CLEARLOG = "clearlogconnect"; @@ -255,7 +257,7 @@ public class LaunchVPN extends Activity { if (!mhideLog && showLogWindow) showLogWindow(); ProfileManager.updateLRU(this, mSelectedProfile); - VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext(), mSelectedProfileReason); + VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext(), mSelectedProfileReason, true); finish(); } } else if (resultCode == Activity.RESULT_CANCELED) { diff --git a/main/src/main/java/de/blinkt/openvpn/OnBootReceiver.java b/main/src/main/java/de/blinkt/openvpn/OnBootReceiver.java index 58c954c9..7033664b 100644 --- a/main/src/main/java/de/blinkt/openvpn/OnBootReceiver.java +++ b/main/src/main/java/de/blinkt/openvpn/OnBootReceiver.java @@ -36,6 +36,6 @@ public class OnBootReceiver extends BroadcastReceiver { } void launchVPN(VpnProfile profile, Context context) { - VPNLaunchHelper.startOpenVpn(profile, context.getApplicationContext(), "on Boot receiver"); + VPNLaunchHelper.startOpenVpn(profile, context.getApplicationContext(), "on Boot receiver", false); } } diff --git a/main/src/main/java/de/blinkt/openvpn/VpnProfile.java b/main/src/main/java/de/blinkt/openvpn/VpnProfile.java index 0da09eb0..f105dd56 100644 --- a/main/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/main/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -5,6 +5,8 @@ package de.blinkt.openvpn; +import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_DO_NOT_REPLACE_RUNNING_VPN; + import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; @@ -31,20 +33,16 @@ import org.spongycastle.util.io.pem.PemWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Serializable; import java.io.StringWriter; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.security.*; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; import java.security.spec.MGF1ParameterSpec; import java.security.spec.PSSParameterSpec; import java.util.Collection; @@ -67,6 +65,8 @@ public class VpnProfile implements Serializable, Cloneable { transient public static final long MAX_EMBED_FILE_SIZE = 2048 * 1024; // 2048kB // Don't change this, not all parts of the program use this constant public static final String EXTRA_PROFILEUUID = "de.blinkt.openvpn.profileUUID"; + public static final String EXTRA_PROFILE_VERSION = "de.blinkt.openvpn.profileVersion"; + public static final String INLINE_TAG = "[[INLINE]]"; public static final String DISPLAYNAME_TAG = "[[NAME]]"; public static final int MAXLOGLEVEL = 4; @@ -816,14 +816,14 @@ public class VpnProfile implements Serializable, Cloneable { cfg.close(); } - public Intent getStartServiceIntent(Context context, String startReason) { - String prefix = context.getPackageName(); - + public Intent getStartServiceIntent(Context context, String startReason, boolean replace_running_vpn) { Intent intent = new Intent(context, OpenVPNService.class); - intent.putExtra(prefix + ".profileUUID", mUuid.toString()); - intent.putExtra(prefix + ".profileVersion", mVersion); + intent.putExtra(EXTRA_PROFILEUUID, mUuid.toString()); + intent.putExtra(EXTRA_PROFILE_VERSION, mVersion); if (startReason != null) - intent.putExtra(prefix + ".startReason", startReason); + intent.putExtra(OpenVPNService.EXTRA_START_REASON, startReason); + if (!replace_running_vpn) + intent.putExtra(EXTRA_DO_NOT_REPLACE_RUNNING_VPN, true); return intent; } diff --git a/main/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java b/main/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java index 6cc170fa..4ccf5bd3 100644 --- a/main/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java +++ b/main/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java @@ -86,7 +86,7 @@ public class DisconnectVPN extends Activity implements DialogInterface.OnClickLi } else if (which == DialogInterface.BUTTON_NEUTRAL) { Intent intent = new Intent(this, LaunchVPN.class); intent.putExtra(LaunchVPN.EXTRA_KEY, VpnStatus.getLastConnectedVPNProfile()); - intent.putExtra(LaunchVPN.EXTRA_START_REASON, "Reconnect button pressed."); + intent.putExtra(OpenVPNService.EXTRA_START_REASON, "Reconnect button pressed."); intent.setAction(Intent.ACTION_MAIN); startActivity(intent); } diff --git a/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java index ab71f00b..2f1f0788 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java @@ -6,7 +6,6 @@ package de.blinkt.openvpn.api; import android.annotation.TargetApi; -import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -14,9 +13,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; import android.net.VpnService; import android.os.Binder; import android.os.Build; @@ -146,11 +142,11 @@ public class ExternalOpenVPNService extends Service implements StateListener { shortVPNIntent.setClass(getBaseContext(), de.blinkt.openvpn.LaunchVPN.class); shortVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_KEY, vp.getUUIDString()); shortVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_HIDELOG, true); - shortVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_START_REASON, startReason); + shortVPNIntent.putExtra(de.blinkt.openvpn.core.OpenVPNService.EXTRA_START_REASON, startReason); shortVPNIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(shortVPNIntent); } else { - VPNLaunchHelper.startOpenVpn(vp, getBaseContext(), startReason); + VPNLaunchHelper.startOpenVpn(vp, getBaseContext(), startReason, true); } } diff --git a/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java b/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java index 22110ad0..55322e7f 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java +++ b/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java @@ -93,7 +93,7 @@ public class RemoteAction extends Activity { } else { Intent startVPN = new Intent(this, LaunchVPN.class); startVPN.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString()); - startVPN.putExtra(LaunchVPN.EXTRA_START_REASON, ".api.ConnectVPN call"); + startVPN.putExtra(OpenVPNService.EXTRA_START_REASON, ".api.ConnectVPN call"); startVPN.setAction(Intent.ACTION_MAIN); startActivity(startVPN); } diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index 983b63f3..c555fd27 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -6,6 +6,8 @@ package de.blinkt.openvpn.core; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static de.blinkt.openvpn.VpnProfile.EXTRA_PROFILEUUID; +import static de.blinkt.openvpn.VpnProfile.EXTRA_PROFILE_VERSION; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; import static de.blinkt.openvpn.core.NetworkSpace.IpAddress; @@ -70,6 +72,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac public static final String START_SERVICE = "de.blinkt.openvpn.START_SERVICE"; public static final String START_SERVICE_STICKY = "de.blinkt.openvpn.START_SERVICE_STICKY"; public static final String ALWAYS_SHOW_NOTIFICATION = "de.blinkt.openvpn.NOTIFICATION_ALWAYS_VISIBLE"; + + public static final String EXTRA_DO_NOT_REPLACE_RUNNING_VPN = "de.blinkt.openvpn.DO_NOT_REPLACE_RUNNING_VPN"; + + public static final String EXTRA_START_REASON = "de.blinkt.openvpn.startReason"; + public static final String DISCONNECT_VPN = "de.blinkt.openvpn.DISCONNECT_VPN"; public static final String NOTIFICATION_CHANNEL_BG_ID = "openvpn_bg"; public static final String NOTIFICATION_CHANNEL_NEWSTATUS_ID = "openvpn_newstat"; @@ -86,6 +93,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac private static final int PRIORITY_MAX = 2; private static boolean mNotificationAlwaysVisible = false; + static class TunConfig { private final Vector mDnslist = new Vector<>(); private final NetworkSpace mRoutes = new NetworkSpace(); @@ -554,45 +562,46 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac private VpnProfile fetchVPNProfile(Intent intent) { + VpnProfile vpnProfile = null; String startReason; - if (intent != null && intent.hasExtra(getPackageName() + ".profileUUID")) { - String profileUUID = intent.getStringExtra(getPackageName() + ".profileUUID"); - int profileVersion = intent.getIntExtra(getPackageName() + ".profileVersion", 0); - startReason = intent.getStringExtra(getPackageName() + ".startReason"); + if (intent != null && intent.hasExtra(EXTRA_PROFILEUUID)) { + String profileUUID = intent.getStringExtra(EXTRA_PROFILEUUID); + int profileVersion = intent.getIntExtra(EXTRA_PROFILE_VERSION, 0); + startReason = intent.getStringExtra(EXTRA_START_REASON); if (startReason == null) startReason = "(unknown)"; // Try for 10s to get current version of the profile - mProfile = ProfileManager.get(this, profileUUID, profileVersion, 100); + vpnProfile = ProfileManager.get(this, profileUUID, profileVersion, 100); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { - updateShortCutUsage(mProfile); + updateShortCutUsage(vpnProfile); } } else { /* The intent is null when we are set as always-on or the service has been restarted. */ - mProfile = ProfileManager.getLastConnectedProfile(this); + vpnProfile = ProfileManager.getLastConnectedProfile(this); startReason = "Using last connected profile (started with null intent, always-on or restart after crash)"; VpnStatus.logInfo(R.string.service_restarted); /* Got no profile, just stop */ - if (mProfile == null) { + if (vpnProfile == null) { startReason = "could not get last connected profile, using default (started with null intent, always-on or restart after crash)"; Log.d("OpenVPN", "Got no last connected profile on null intent. Assuming always on."); - mProfile = ProfileManager.getAlwaysOnVPN(this); + vpnProfile = ProfileManager.getAlwaysOnVPN(this); - if (mProfile == null) { + if (vpnProfile == null) { return null; } } /* Do the asynchronous keychain certificate stuff */ - mProfile.checkForRestart(this); + vpnProfile.checkForRestart(this); } String name = "(null)"; - if (mProfile != null) - name = mProfile.getName(); + if (vpnProfile != null) + name = vpnProfile.getName(); VpnStatus.logDebug(String.format("Fetched VPN profile (%s) triggered by %s", name, startReason)); - return mProfile; + return vpnProfile; } private boolean checkVPNPermission(VpnProfile startprofile) { @@ -608,7 +617,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac Intent launchVPNIntent = new Intent(this, LaunchVPN.class); launchVPNIntent.putExtra(LaunchVPN.EXTRA_KEY, startprofile.getUUIDString()); - launchVPNIntent.putExtra(LaunchVPN.EXTRA_START_REASON, "OpenService lacks permission"); + launchVPNIntent.putExtra(EXTRA_START_REASON, "OpenService lacks permission"); launchVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_HIDELOG, true); launchVPNIntent.addFlags(FLAG_ACTIVITY_NEW_TASK); launchVPNIntent.setAction(Intent.ACTION_MAIN); @@ -633,8 +642,23 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac if (!checkVPNPermission(vp)) return; - ProfileManager.setConnectedVpnProfile(this, mProfile); - VpnStatus.setConnectedVPNProfile(mProfile.getUUIDString()); + boolean noReplaceRequested = (intent != null) && intent.getBooleanExtra(EXTRA_DO_NOT_REPLACE_RUNNING_VPN, false); + + + /* we get an empty start request or explicitly get told to not replace the VPN then ignore + * a start request. This avoids OnBootreciver, Always and user quickly clicking to have + * weird race conditions + */ + if (mProfile != null && mProfile == vp && (intent == null || noReplaceRequested)) + { + /* we do not want to replace the running VPN */ + VpnStatus.logInfo("VPN already running. Ignoring request to start VPN"); + return; + } + + mProfile = vp; + ProfileManager.setConnectedVpnProfile(this, vp); + VpnStatus.setConnectedVPNProfile(vp.getUUIDString()); keepVPNAlive.scheduleKeepVPNAliveJobService(this, vp); String nativeLibraryDirectory = getApplicationInfo().nativeLibraryDir; diff --git a/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java b/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java index bc04bc5e..0784361c 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java +++ b/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java @@ -100,8 +100,8 @@ public class VPNLaunchHelper { } - public static void startOpenVpn(VpnProfile startprofile, Context context, String startReason) { - Intent startVPN = startprofile.getStartServiceIntent(context, startReason); + public static void startOpenVpn(VpnProfile startprofile, Context context, String startReason, boolean replace_running_vpn) { + Intent startVPN = startprofile.getStartServiceIntent(context, startReason, replace_running_vpn); if (startVPN != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) //noinspection NewApi diff --git a/main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java b/main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java index b4264aba..130dc68c 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java +++ b/main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java @@ -49,7 +49,7 @@ public class keepVPNAlive extends JobService implements VpnStatus.StateListener unscheduleKeepVPNAliveJobService(this); return false; } - VPNLaunchHelper.startOpenVpn(vp, getApplicationContext(), "VPN keep alive Job"); + VPNLaunchHelper.startOpenVpn(vp, getApplicationContext(), "VPN keep alive Job", false); } else { VpnStatus.logDebug("Keepalive service called but VPN still connected."); } diff --git a/main/src/ui/java/de/blinkt/openvpn/OpenVPNTileService.java b/main/src/ui/java/de/blinkt/openvpn/OpenVPNTileService.java index 94c1f1db..09593047 100644 --- a/main/src/ui/java/de/blinkt/openvpn/OpenVPNTileService.java +++ b/main/src/ui/java/de/blinkt/openvpn/OpenVPNTileService.java @@ -85,7 +85,7 @@ public class OpenVPNTileService extends TileService implements VpnStatus.StateLi @SuppressLint("Override") @TargetApi(Build.VERSION_CODES.N) void launchVPN(VpnProfile profile, Context context) { - VPNLaunchHelper.startOpenVpn(profile, getBaseContext(), "QuickTile"); + VPNLaunchHelper.startOpenVpn(profile, getBaseContext(), "QuickTile", true); } @TargetApi(Build.VERSION_CODES.N) diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/CreateShortcuts.java b/main/src/ui/java/de/blinkt/openvpn/activities/CreateShortcuts.java index 82455895..3b9312e5 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/CreateShortcuts.java +++ b/main/src/ui/java/de/blinkt/openvpn/activities/CreateShortcuts.java @@ -5,6 +5,8 @@ package de.blinkt.openvpn.activities; +import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_START_REASON; + import android.app.ListActivity; import android.content.Intent; import android.os.Bundle; @@ -126,7 +128,7 @@ public class CreateShortcuts extends ListActivity implements OnItemClickListener Intent shortcutIntent = new Intent(Intent.ACTION_MAIN); shortcutIntent.setClass(this, LaunchVPN.class); shortcutIntent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString()); - shortcutIntent.putExtra(LaunchVPN.EXTRA_START_REASON, "shortcut"); + shortcutIntent.putExtra(EXTRA_START_REASON, "shortcut"); // Then, set up the container intent (the response to the caller) diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/LogFragment.java b/main/src/ui/java/de/blinkt/openvpn/fragments/LogFragment.java index c5c48b0e..9ce65316 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/LogFragment.java +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/LogFragment.java @@ -538,7 +538,7 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar. (dialog1, which) -> { Intent intent = new Intent(getActivity(), LaunchVPN.class); intent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUIDString()); - intent.putExtra(LaunchVPN.EXTRA_START_REASON, "restart from logwindow"); + intent.putExtra(OpenVPNService.EXTRA_START_REASON, "restart from logwindow"); intent.setAction(Intent.ACTION_MAIN); startActivity(intent); }); diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java b/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java index fa9438cb..5b4c736f 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java @@ -68,6 +68,7 @@ import de.blinkt.openvpn.core.VpnStatus; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; import static de.blinkt.openvpn.core.OpenVPNService.DISCONNECT_VPN; import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_CHALLENGE_TXT; +import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_START_REASON; public class VPNProfileList extends ListFragment implements OnClickListener, VpnStatus.StateListener { @@ -242,7 +243,7 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn shortcutIntent.setClass(requireContext(), LaunchVPN.class); shortcutIntent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString()); shortcutIntent.setAction(Intent.ACTION_MAIN); - shortcutIntent.putExtra(LaunchVPN.EXTRA_START_REASON, "shortcut"); + shortcutIntent.putExtra(EXTRA_START_REASON, "shortcut"); shortcutIntent.putExtra("EXTRA_HIDELOG", true); PersistableBundle versionExtras = new PersistableBundle(); @@ -563,7 +564,7 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn Intent intent = new Intent(getActivity(), LaunchVPN.class); intent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString()); - intent.putExtra(LaunchVPN.EXTRA_START_REASON, "main profile list"); + intent.putExtra(EXTRA_START_REASON, "main profile list"); intent.setAction(Intent.ACTION_MAIN); startActivity(intent); } -- cgit v1.2.3 From a067d0f480cda0e1d92572c411df1a8f6efac125 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 30 Nov 2023 11:56:16 +0100 Subject: Avoid replacing ongoing notification with "building config.." notification --- .../de/blinkt/openvpn/core/OpenVPNService.java | 22 +++++++++++++++++----- main/src/main/res/values/strings.xml | 1 + 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'main/src') diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index c555fd27..6f20d414 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -13,6 +13,7 @@ import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INP import static de.blinkt.openvpn.core.NetworkSpace.IpAddress; import android.Manifest.permission; +import android.annotation.TargetApi; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -39,6 +40,7 @@ import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.service.notification.StatusBarNotification; import android.system.OsConstants; import android.text.TextUtils; import android.util.Base64; @@ -113,7 +115,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac private Thread mProcessThread = null; private VpnProfile mProfile; - private DeviceStateReceiver mDeviceStateReceiver; private boolean mDisplayBytecount = false; private boolean mStarting = false; @@ -537,10 +538,13 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac // Always show notification here to avoid problem with startForeground timeout VpnStatus.logInfo(R.string.building_configration); - VpnStatus.updateStateString("VPN_GENERATE_CONFIG", "", R.string.building_configration, ConnectionStatus.LEVEL_START); - showNotification(VpnStatus.getLastCleanLogMessage(this), - VpnStatus.getLastCleanLogMessage(this), NOTIFICATION_CHANNEL_NEWSTATUS_ID, 0, ConnectionStatus.LEVEL_START, null); + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M || (!foregroundNotificationVisible())) { + + VpnStatus.updateStateString("VPN_GENERATE_CONFIG", "", R.string.building_configration, ConnectionStatus.LEVEL_START); + showNotification(VpnStatus.getLastCleanLogMessage(this), + VpnStatus.getLastCleanLogMessage(this), NOTIFICATION_CHANNEL_NEWSTATUS_ID, 0, ConnectionStatus.LEVEL_START, null); + } /* start the OpenVPN process itself in a background thread */ mCommandHandler.post(() -> startOpenVPN(intent, startId)); @@ -548,6 +552,14 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac return START_STICKY; } + @TargetApi(Build.VERSION_CODES.M) + private boolean foregroundNotificationVisible() { + NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + StatusBarNotification[] notifications = mNotificationManager.getActiveNotifications(); + /* Assume for simplicity that all our notifications are foreground */ + return notifications.length > 0; + } + @RequiresApi(Build.VERSION_CODES.N_MR1) private void updateShortCutUsage(VpnProfile profile) { if (profile == null) @@ -652,7 +664,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac if (mProfile != null && mProfile == vp && (intent == null || noReplaceRequested)) { /* we do not want to replace the running VPN */ - VpnStatus.logInfo("VPN already running. Ignoring request to start VPN"); + VpnStatus.logInfo(R.string.ignore_vpn_start_request, mProfile.getName()); return; } diff --git a/main/src/main/res/values/strings.xml b/main/src/main/res/values/strings.xml index 88f98a17..fd0b30ce 100755 --- a/main/src/main/res/values/strings.xml +++ b/main/src/main/res/values/strings.xml @@ -510,4 +510,5 @@ Username Permission to start a VPN connection is required VPN Service is missing permission to connect a VPN. Requesting permission via notification. + VPN already running (%s). Ignoring request to start VPN. -- cgit v1.2.3 From 279dc0a51c1d0838f653ef727af6ebcef3323ecf Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 30 Nov 2023 13:11:24 +0100 Subject: Update OpenVPN and OpenVPN 3.x --- main/src/main/cpp/openvpn | 2 +- main/src/main/cpp/openvpn3 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'main/src') diff --git a/main/src/main/cpp/openvpn b/main/src/main/cpp/openvpn index eebb6934..0ad44976 160000 --- a/main/src/main/cpp/openvpn +++ b/main/src/main/cpp/openvpn @@ -1 +1 @@ -Subproject commit eebb69344ba57456ec7f2e6b0c692583f5f5e8ab +Subproject commit 0ad449769ee88fe19fb23a0714639f98eba77088 diff --git a/main/src/main/cpp/openvpn3 b/main/src/main/cpp/openvpn3 index 697e4134..7f2e42ce 160000 --- a/main/src/main/cpp/openvpn3 +++ b/main/src/main/cpp/openvpn3 @@ -1 +1 @@ -Subproject commit 697e413435066fdf617cad1e0ba0f67144f2298e +Subproject commit 7f2e42ce0ba6651f6549146f641f1e4c196059a4 -- cgit v1.2.3 From 4473ad1f1bc49c166fb8ab92ee7a7b91c608135e Mon Sep 17 00:00:00 2001 From: Elizaveta Date: Mon, 22 Apr 2024 16:50:45 +0300 Subject: Fix binding to external authenticator app on Android 14+ External authenticator apps may need to start background activities (for example, to allow users enter a pin code), but starting from Android 14, if the app bound to the service is targeting Android 14 or higher, it no longer allows the app that has the service to start a background activity by default. We need to add flag BIND_ALLOW_ACTIVITY_STARTS to allow the external authenticator app to start background activities. --- main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'main/src') diff --git a/main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java b/main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java index 39151646..0da8abbb 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java +++ b/main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java @@ -215,8 +215,9 @@ public class ExtAuthHelper { Intent intent = new Intent(ACTION_CERT_PROVIDER); intent.setPackage(packagename); - if (!context.bindService(intent, extAuthServiceConnection, Context.BIND_AUTO_CREATE)) { - throw new KeyChainException("could not bind to external authticator app: " + packagename); + if (!context.bindService(intent, extAuthServiceConnection, + Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_ACTIVITY_STARTS)) { + throw new KeyChainException("could not bind to external authenticator app: " + packagename); } return new ExternalAuthProviderConnection(context, extAuthServiceConnection, q.take()); } -- cgit v1.2.3 From 5bdac9a6be1716738bd90816247fd52672a16568 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 12 Dec 2023 12:15:40 +0100 Subject: Fix a few accessibility issues reported by pre check of Play store --- main/src/main/res/values/strings.xml | 1 + main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java | 1 + main/src/ui/res/layout/basic_settings.xml | 1 + main/src/ui/res/layout/log_silders.xml | 3 ++- main/src/ui/res/layout/server_card.xml | 2 ++ main/src/ui/res/menu/connections.xml | 1 + 6 files changed, 8 insertions(+), 1 deletion(-) (limited to 'main/src') diff --git a/main/src/main/res/values/strings.xml b/main/src/main/res/values/strings.xml index fd0b30ce..53893699 100755 --- a/main/src/main/res/values/strings.xml +++ b/main/src/main/res/values/strings.xml @@ -511,4 +511,5 @@ Permission to start a VPN connection is required VPN Service is missing permission to connect a VPN. Requesting permission via notification. VPN already running (%s). Ignoring request to start VPN. + Name of the VPN Profile diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java b/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java index 5b4c736f..28504268 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java @@ -451,6 +451,7 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn if (context != null) { final EditText entry = new EditText(context); entry.setSingleLine(); + entry.setContentDescription(getString(R.string.name_of_the_vpn_profile)); AlertDialog.Builder dialog = new AlertDialog.Builder(context); if (mCopyProfile == null) diff --git a/main/src/ui/res/layout/basic_settings.xml b/main/src/ui/res/layout/basic_settings.xml index 8aa4c811..47f84e5f 100644 --- a/main/src/ui/res/layout/basic_settings.xml +++ b/main/src/ui/res/layout/basic_settings.xml @@ -21,6 +21,7 @@ style="@style/item" android:text="@string/profilename" android:textAppearance="?android:attr/textAppearanceSmall" + android:labelFor="@id/profilename" /> + android:text="@string/log_verbosity_level" + android:labelFor="@id/LogLevelSlider"/> @@ -364,6 +365,7 @@ android:id="@+id/warnung_custom" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:labelFor="@id/customoptions" android:text="@string/custom_connection_options_warng"/> \ No newline at end of file -- cgit v1.2.3 From 879ed38be52fbc1d7079ced9c31756c7635a1fa1 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 23 Jul 2024 14:18:13 +0200 Subject: Small coverity fixes --- main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main/src') diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index 6f20d414..a1411b5e 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -309,7 +309,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac nbuilder.setOngoing(true); nbuilder.setSmallIcon(icon); - if (status == LEVEL_WAITING_FOR_USER_INPUT) { + if (status == LEVEL_WAITING_FOR_USER_INPUT && intent != null) { PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE); nbuilder.setContentIntent(pIntent); } else { -- cgit v1.2.3 From aae95613927ad80794bb5683208172aa6269bd23 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 23 Jul 2024 15:00:57 +0200 Subject: Update version of OpenSSL, OpenVPN 2/3, Asio and many libraries --- main/src/main/cpp/asio | 2 +- main/src/main/cpp/openssl | 2 +- main/src/main/cpp/openvpn | 2 +- main/src/main/cpp/openvpn3 | 2 +- main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java | 1 - 5 files changed, 4 insertions(+), 5 deletions(-) (limited to 'main/src') diff --git a/main/src/main/cpp/asio b/main/src/main/cpp/asio index 1f8d1548..12e0ce9e 160000 --- a/main/src/main/cpp/asio +++ b/main/src/main/cpp/asio @@ -1 +1 @@ -Subproject commit 1f8d154829b902dbc45a651587c6c6df948358e8 +Subproject commit 12e0ce9e0500bf0f247dbd1ae894272656456079 diff --git a/main/src/main/cpp/openssl b/main/src/main/cpp/openssl index 479b1b83..bbc7c1c1 160000 --- a/main/src/main/cpp/openssl +++ b/main/src/main/cpp/openssl @@ -1 +1 @@ -Subproject commit 479b1b83891105c382cacdf71aeb35c14e994219 +Subproject commit bbc7c1c11fbd0eb47e3d2ee46c9986ce16b3e8a5 diff --git a/main/src/main/cpp/openvpn b/main/src/main/cpp/openvpn index 0ad44976..99788b64 160000 --- a/main/src/main/cpp/openvpn +++ b/main/src/main/cpp/openvpn @@ -1 +1 @@ -Subproject commit 0ad449769ee88fe19fb23a0714639f98eba77088 +Subproject commit 99788b64e6aa82c32aa39915c441e0b3b9164545 diff --git a/main/src/main/cpp/openvpn3 b/main/src/main/cpp/openvpn3 index 7f2e42ce..13d6b06e 160000 --- a/main/src/main/cpp/openvpn3 +++ b/main/src/main/cpp/openvpn3 @@ -1 +1 @@ -Subproject commit 7f2e42ce0ba6651f6549146f641f1e4c196059a4 +Subproject commit 13d6b06e1c03174000f0a7bdfdcfb680e19f4cb8 diff --git a/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java b/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java index ad7a7c28..4f8e33a6 100644 --- a/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java +++ b/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java @@ -262,7 +262,6 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable void setUserPW() { if (mVp.isUserPWAuth()) { ClientAPI_ProvideCreds creds = new ClientAPI_ProvideCreds(); - creds.setCachePassword(true); creds.setPassword(mVp.getPasswordAuth()); creds.setUsername(mVp.mUsername); provide_creds(creds); -- cgit v1.2.3 From 6b0a2e59b20fa328ff7f82afb6867f9f8e14e344 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Fri, 26 Jul 2024 15:26:17 +0200 Subject: Move to viewpager2 --- .../de/blinkt/openvpn/activities/MainActivity.kt | 14 +- .../blinkt/openvpn/activities/VPNPreferences.java | 220 --------------------- .../de/blinkt/openvpn/activities/VPNPreferences.kt | 208 +++++++++++++++++++ .../openvpn/views/ScreenSlidePagerAdapter.java | 80 -------- .../openvpn/views/ScreenSlidePagerAdapter.kt | 59 ++++++ main/src/ui/res/layout/main_activity.xml | 27 ++- 6 files changed, 291 insertions(+), 317 deletions(-) delete mode 100644 main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.java create mode 100644 main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.kt delete mode 100644 main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.java create mode 100644 main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.kt (limited to 'main/src') diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/MainActivity.kt b/main/src/ui/java/de/blinkt/openvpn/activities/MainActivity.kt index 68117b52..49778b88 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/MainActivity.kt +++ b/main/src/ui/java/de/blinkt/openvpn/activities/MainActivity.kt @@ -11,23 +11,26 @@ import android.view.Menu import android.view.MenuItem import android.widget.Toast import androidx.viewpager.widget.ViewPager +import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator import de.blinkt.openvpn.R import de.blinkt.openvpn.fragments.* import de.blinkt.openvpn.fragments.ImportRemoteConfig.Companion.newInstance import de.blinkt.openvpn.views.ScreenSlidePagerAdapter class MainActivity : BaseActivity() { - private lateinit var mPager: ViewPager + private lateinit var mPager: ViewPager2 private lateinit var mPagerAdapter: ScreenSlidePagerAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) - // Instantiate a ViewPager and a PagerAdapter. mPager = findViewById(R.id.pager) - mPagerAdapter = ScreenSlidePagerAdapter(supportFragmentManager, this) + val tablayout: TabLayout = findViewById(R.id.tab_layout) + + mPagerAdapter = ScreenSlidePagerAdapter(supportFragmentManager, lifecycle, this) /* Toolbar and slider should have the same elevation */disableToolbarElevation() mPagerAdapter.addTab(R.string.vpn_list_title, VPNProfileList::class.java) @@ -41,6 +44,11 @@ class MainActivity : BaseActivity() { mPagerAdapter.addTab(R.string.openvpn_log, LogFragment::class.java) mPagerAdapter.addTab(R.string.about, AboutFragment::class.java) mPager.setAdapter(mPagerAdapter) + + TabLayoutMediator(tablayout, mPager) { tab, position -> + tab.text = mPagerAdapter.getPageTitle(position) + }.attach() + } private fun disableToolbarElevation() { diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.java b/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.java deleted file mode 100644 index 2c9eb761..00000000 --- a/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2012-2016 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.activities; - -import android.annotation.TargetApi; -import android.app.AlertDialog; -import android.content.Intent; -import android.os.Build; -import android.os.Bundle; -import android.preference.PreferenceActivity; -import android.view.Menu; -import android.view.MenuItem; -import android.widget.Toast; - -import androidx.appcompat.app.ActionBar; -import androidx.viewpager.widget.ViewPager; - -import de.blinkt.openvpn.R; -import de.blinkt.openvpn.VpnProfile; -import de.blinkt.openvpn.core.ProfileManager; -import de.blinkt.openvpn.fragments.Settings_Allowed_Apps; -import de.blinkt.openvpn.fragments.Settings_Authentication; -import de.blinkt.openvpn.fragments.Settings_Basic; -import de.blinkt.openvpn.fragments.Settings_Connections; -import de.blinkt.openvpn.fragments.Settings_IP; -import de.blinkt.openvpn.fragments.Settings_Obscure; -import de.blinkt.openvpn.fragments.Settings_Routing; -import de.blinkt.openvpn.fragments.Settings_UserEditable; -import de.blinkt.openvpn.fragments.ShowConfigFragment; -import de.blinkt.openvpn.fragments.VPNProfileList; -import de.blinkt.openvpn.views.ScreenSlidePagerAdapter; - - -public class VPNPreferences extends BaseActivity { - - static final Class[] validFragments = new Class[]{ - Settings_Authentication.class, Settings_Basic.class, Settings_IP.class, - Settings_Obscure.class, Settings_Routing.class, ShowConfigFragment.class, - Settings_Connections.class, Settings_Allowed_Apps.class, - }; - - private String mProfileUUID; - private VpnProfile mProfile; - private ViewPager mPager; - private ScreenSlidePagerAdapter mPagerAdapter; - - public VPNPreferences() { - super(); - } - - - @TargetApi(Build.VERSION_CODES.KITKAT) - protected boolean isValidFragment(String fragmentName) { - for (Class c: validFragments) - if (c.getName().equals(fragmentName)) - return true; - return false; - - } - - @Override - protected void onStop() { - super.onStop(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - outState.putString(getIntent().getStringExtra(getPackageName() + ".profileUUID"),mProfileUUID); - super.onSaveInstanceState(outState); - } - - @Override - protected void onResume() { - super.onResume(); - getProfile(); - // When a profile is deleted from a category fragment in hadset mod we need to finish - // this activity as well when returning - if (mProfile==null || mProfile.profileDeleted) { - setResult(VPNProfileList.RESULT_VPN_DELETED); - finish(); - } - if (mProfile.mTemporaryProfile) - { - Toast.makeText(this, "Temporary profiles cannot be edited", Toast.LENGTH_LONG).show(); - finish(); - } - } - - private void getProfile() { - Intent intent = getIntent(); - - if(intent!=null) { - String profileUUID = intent.getStringExtra(getPackageName() + ".profileUUID"); - if(profileUUID==null) { - Bundle initialArguments = getIntent().getBundleExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS); - profileUUID = initialArguments.getString(getPackageName() + ".profileUUID"); - } - if(profileUUID!=null){ - - mProfileUUID = profileUUID; - mProfile = ProfileManager.get(this, mProfileUUID); - - } - } - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - mProfileUUID = getIntent().getStringExtra(getPackageName() + ".profileUUID"); - if(savedInstanceState!=null){ - String savedUUID = savedInstanceState.getString(getPackageName() + ".profileUUID"); - if(savedUUID!=null) - mProfileUUID=savedUUID; - } - super.onCreate(savedInstanceState); - - mProfile = ProfileManager.get(this,mProfileUUID); - if(mProfile==null) { - Toast.makeText(this, "Profile to edit cannot be found.", Toast.LENGTH_LONG).show(); - finish(); - return; - } - - setTitle(getString(R.string.edit_profile_title, mProfile.getName())); - - - setContentView(R.layout.main_activity); - - disableToolbarElevation(); - - // Instantiate a ViewPager and a PagerAdapter. - mPager = findViewById(R.id.pager); - mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager(), this); - - - Bundle fragmentArguments = new Bundle(); - fragmentArguments.putString(getPackageName() + ".profileUUID",mProfileUUID); - mPagerAdapter.setFragmentArgs(fragmentArguments); - - if (mProfile.mUserEditable) { - mPagerAdapter.addTab(R.string.basic, Settings_Basic.class); - mPagerAdapter.addTab(R.string.server_list, Settings_Connections.class); - mPagerAdapter.addTab(R.string.ipdns, Settings_IP.class); - mPagerAdapter.addTab(R.string.routing, Settings_Routing.class); - mPagerAdapter.addTab(R.string.settings_auth, Settings_Authentication.class); - - mPagerAdapter.addTab(R.string.advanced, Settings_Obscure.class); - } else { - mPagerAdapter.addTab(R.string.basic, Settings_UserEditable.class); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - mPagerAdapter.addTab(R.string.vpn_allowed_apps, Settings_Allowed_Apps.class); - } - mPagerAdapter.addTab(R.string.generated_config, ShowConfigFragment.class); - - - mPager.setAdapter(mPagerAdapter); - - //TabBarView tabs = (TabBarView) findViewById(R.id.sliding_tabs); - //tabs.setViewPager(mPager); - - } - - - @Override - public void onBackPressed() { - setResult(RESULT_OK, getIntent()); - super.onBackPressed(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.remove_vpn) - askProfileRemoval(); - if (item.getItemId() == R.id.duplicate_vpn) { - Intent data = new Intent(); - data.putExtra(VpnProfile.EXTRA_PROFILEUUID, mProfileUUID); - setResult(VPNProfileList.RESULT_VPN_DUPLICATE, data); - finish(); - } - - return super.onOptionsItemSelected(item); - } - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - - getMenuInflater().inflate(R.menu.vpnpreferences_menu, menu); - - return super.onCreateOptionsMenu(menu); - } - - private void askProfileRemoval() { - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setTitle("Confirm deletion"); - dialog.setMessage(getString(R.string.remove_vpn_query, mProfile.mName)); - - dialog.setPositiveButton(android.R.string.yes, - (dialog1, which) -> removeProfile(mProfile)); - dialog.setNegativeButton(android.R.string.no,null); - dialog.create().show(); - } - - protected void removeProfile(VpnProfile profile) { - ProfileManager.getInstance(this).removeProfile(this,profile); - setResult(VPNProfileList.RESULT_VPN_DELETED); - finish(); - - } - - private void disableToolbarElevation() { - ActionBar toolbar = getSupportActionBar(); - toolbar.setElevation(0); - } - -} diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.kt b/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.kt new file mode 100644 index 00000000..fd9fd43e --- /dev/null +++ b/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.kt @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2012-2016 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ +package de.blinkt.openvpn.activities + +import android.annotation.TargetApi +import android.app.AlertDialog +import android.content.DialogInterface +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.preference.PreferenceActivity +import android.view.Menu +import android.view.MenuItem +import android.widget.Toast +import androidx.viewpager2.widget.ViewPager2 +import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator +import de.blinkt.openvpn.R +import de.blinkt.openvpn.VpnProfile +import de.blinkt.openvpn.core.ProfileManager +import de.blinkt.openvpn.fragments.Settings_Allowed_Apps +import de.blinkt.openvpn.fragments.Settings_Authentication +import de.blinkt.openvpn.fragments.Settings_Basic +import de.blinkt.openvpn.fragments.Settings_Connections +import de.blinkt.openvpn.fragments.Settings_IP +import de.blinkt.openvpn.fragments.Settings_Obscure +import de.blinkt.openvpn.fragments.Settings_Routing +import de.blinkt.openvpn.fragments.Settings_UserEditable +import de.blinkt.openvpn.fragments.ShowConfigFragment +import de.blinkt.openvpn.fragments.VPNProfileList +import de.blinkt.openvpn.views.ScreenSlidePagerAdapter + +class VPNPreferences : BaseActivity() { + private var mProfileUUID: String? = null + private var mProfile: VpnProfile? = null + private lateinit var mPager: ViewPager2 + private lateinit var mPagerAdapter: ScreenSlidePagerAdapter + + @TargetApi(Build.VERSION_CODES.KITKAT) + protected fun isValidFragment(fragmentName: String): Boolean { + for (c in validFragments) if (c.name == fragmentName) return true + return false + } + + override fun onStop() { + super.onStop() + } + + override fun onSaveInstanceState(outState: Bundle) { + outState.putString(intent.getStringExtra("$packageName.profileUUID"), mProfileUUID) + super.onSaveInstanceState(outState) + } + + override fun onResume() { + super.onResume() + profile + // When a profile is deleted from a category fragment in hadset mod we need to finish + // this activity as well when returning + if (mProfile == null || mProfile!!.profileDeleted) { + setResult(VPNProfileList.RESULT_VPN_DELETED) + finish() + } + if (mProfile!!.mTemporaryProfile) { + Toast.makeText(this, "Temporary profiles cannot be edited", Toast.LENGTH_LONG).show() + finish() + } + } + + private val profile: Unit + get() { + val intent = intent + + if (intent != null) { + var profileUUID = intent.getStringExtra("$packageName.profileUUID") + if (profileUUID == null) { + val initialArguments = + getIntent().getBundleExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS) + profileUUID = initialArguments!!.getString("$packageName.profileUUID") + } + if (profileUUID != null) { + mProfileUUID = profileUUID + mProfile = ProfileManager.get(this, mProfileUUID) + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + mProfileUUID = intent.getStringExtra("$packageName.profileUUID") + if (savedInstanceState != null) { + val savedUUID = savedInstanceState.getString("$packageName.profileUUID") + if (savedUUID != null) mProfileUUID = savedUUID + } + super.onCreate(savedInstanceState) + + mProfile = ProfileManager.get(this, mProfileUUID) + if (mProfile == null) { + Toast.makeText(this, "Profile to edit cannot be found.", Toast.LENGTH_LONG).show() + finish() + return + } + + title = getString(R.string.edit_profile_title, mProfile!!.name) + + + setContentView(R.layout.main_activity) + + disableToolbarElevation() + + // Instantiate a ViewPager and a PagerAdapter. + mPager = findViewById(R.id.pager) + val tablayout: TabLayout = findViewById(R.id.tab_layout) + mPagerAdapter = ScreenSlidePagerAdapter(supportFragmentManager, lifecycle, this) + + + val fragmentArguments = Bundle() + fragmentArguments.putString("$packageName.profileUUID", mProfileUUID) + mPagerAdapter.setFragmentArgs(fragmentArguments) + + if (mProfile!!.mUserEditable) { + mPagerAdapter.addTab(R.string.basic, Settings_Basic::class.java) + mPagerAdapter.addTab(R.string.server_list, Settings_Connections::class.java) + mPagerAdapter.addTab(R.string.ipdns, Settings_IP::class.java) + mPagerAdapter.addTab(R.string.routing, Settings_Routing::class.java) + mPagerAdapter.addTab(R.string.settings_auth, Settings_Authentication::class.java) + + mPagerAdapter.addTab(R.string.advanced, Settings_Obscure::class.java) + } else { + mPagerAdapter.addTab(R.string.basic, Settings_UserEditable::class.java) + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + mPagerAdapter.addTab(R.string.vpn_allowed_apps, Settings_Allowed_Apps::class.java) + } + mPagerAdapter.addTab(R.string.generated_config, ShowConfigFragment::class.java) + + + mPager.setAdapter(mPagerAdapter) + + //TabBarView tabs = (TabBarView) findViewById(R.id.sliding_tabs); + //tabs.setViewPager(mPager); + + TabLayoutMediator(tablayout, mPager) { tab, position -> + tab.text = mPagerAdapter.getPageTitle(position) + }.attach() + } + + + override fun onBackPressed() { + setResult(RESULT_OK, intent) + super.onBackPressed() + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (item.itemId == R.id.remove_vpn) askProfileRemoval() + if (item.itemId == R.id.duplicate_vpn) { + val data = Intent() + data.putExtra(VpnProfile.EXTRA_PROFILEUUID, mProfileUUID) + setResult(VPNProfileList.RESULT_VPN_DUPLICATE, data) + finish() + } + + return super.onOptionsItemSelected(item) + } + + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.vpnpreferences_menu, menu) + + return super.onCreateOptionsMenu(menu) + } + + private fun askProfileRemoval() { + val dialog = AlertDialog.Builder(this) + dialog.setTitle("Confirm deletion") + dialog.setMessage(getString(R.string.remove_vpn_query, mProfile!!.mName)) + + dialog.setPositiveButton( + android.R.string.yes + ) { dialog1: DialogInterface?, which: Int -> removeProfile(mProfile) } + dialog.setNegativeButton(android.R.string.no, null) + dialog.create().show() + } + + protected fun removeProfile(profile: VpnProfile?) { + ProfileManager.getInstance(this).removeProfile(this, profile) + setResult(VPNProfileList.RESULT_VPN_DELETED) + finish() + } + + private fun disableToolbarElevation() { + val toolbar = supportActionBar + toolbar!!.elevation = 0f + } + + companion object { + val validFragments: Array> = arrayOf( + Settings_Authentication::class.java, + Settings_Basic::class.java, + Settings_IP::class.java, + Settings_Obscure::class.java, + Settings_Routing::class.java, + ShowConfigFragment::class.java, + Settings_Connections::class.java, + Settings_Allowed_Apps::class.java, + ) + } +} diff --git a/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.java b/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.java deleted file mode 100644 index 4f1150a2..00000000 --- a/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2012-2016 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.views; - -import android.content.Context; -import android.content.res.Resources; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; - -import java.util.Vector; - -/** -* Created by arne on 18.11.14. -*/ -public class ScreenSlidePagerAdapter extends FragmentPagerAdapter { - - private final Resources res; - private Bundle mFragmentArguments; - - public void setFragmentArgs(Bundle fragmentArguments) { - mFragmentArguments = fragmentArguments; - } - - static class Tab { - public Class fragmentClass; - String mName; - - public Tab(Class fClass, String name){ - mName = name; - fragmentClass = fClass; - } - - } - - - private Vector mTabs = new Vector(); - - public ScreenSlidePagerAdapter(FragmentManager fm, Context c) { - super(fm); - res = c.getResources(); - } - - @NonNull - @Override - public Fragment getItem(int position) { - try { - Fragment fragment = mTabs.get(position).fragmentClass.newInstance(); - if (mFragmentArguments!=null) - fragment.setArguments(mFragmentArguments); - return fragment; - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public CharSequence getPageTitle(int position) { - return mTabs.get(position).mName; - } - - @Override - public int getCount() { - return mTabs.size(); - } - - public void addTab(@StringRes int name, Class fragmentClass) { - mTabs.add(new Tab(fragmentClass, res.getString(name))); - } -} diff --git a/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.kt b/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.kt new file mode 100644 index 00000000..0ce0afaa --- /dev/null +++ b/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012-2016 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ +package de.blinkt.openvpn.views + +import android.content.Context +import android.content.res.Resources +import android.os.Bundle +import androidx.annotation.StringRes +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.lifecycle.Lifecycle +import androidx.viewpager2.adapter.FragmentStateAdapter +import java.util.Vector + +/** + * Created by arne on 18.11.14. + */ +class ScreenSlidePagerAdapter(fm: FragmentManager, lc: Lifecycle, c: Context) : + FragmentStateAdapter( + fm, lc + ) { + private val res: Resources = c.resources + private var mFragmentArguments: Bundle? = null + + fun setFragmentArgs(fragmentArguments: Bundle?) { + mFragmentArguments = fragmentArguments + } + + internal class Tab(var fragmentClass: Class, var mName: String) + + private val mTabs = Vector() + + override fun createFragment(position: Int): Fragment { + try { + val fragment = mTabs[position].fragmentClass.newInstance() + if (mFragmentArguments != null) fragment.arguments = mFragmentArguments + return fragment + } catch (e: InstantiationException) { + e.printStackTrace() + } catch (e: IllegalAccessException) { + e.printStackTrace() + } + throw IndexOutOfBoundsException("index wrong") + } + + fun getPageTitle(position: Int): CharSequence { + return mTabs[position].mName + } + + override fun getItemCount(): Int { + return mTabs.size + } + + fun addTab(@StringRes name: Int, fragmentClass: Class) { + mTabs.add(Tab(fragmentClass, res.getString(name))) + } +} diff --git a/main/src/ui/res/layout/main_activity.xml b/main/src/ui/res/layout/main_activity.xml index b2fe2251..edc64ece 100644 --- a/main/src/ui/res/layout/main_activity.xml +++ b/main/src/ui/res/layout/main_activity.xml @@ -9,23 +9,22 @@ android:layout_height="match_parent" android:orientation="vertical"> - - + android:layout_height="wrap_content" + android:layout_gravity="top" + app:tabMode="scrollable" - - /> + - -- cgit v1.2.3 From 291acb38ddf8cf8c8f7dab2f1aad6bb860ae6109 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Fri, 26 Jul 2024 15:30:22 +0200 Subject: Update versions and enable Android V build --- main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main/src') diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt b/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt index 1a16829e..e46356e9 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt +++ b/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt @@ -94,7 +94,7 @@ class InternalWebView : AppCompatActivity() { } - override fun onNewIntent(intent: Intent?) { + override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) } -- cgit v1.2.3 From c2d625eef66c2ede30f0e5c8d03ca279975eefc8 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Mon, 29 Jul 2024 17:21:39 +0200 Subject: Implement enough of edge-to-edge to work well on Android V --- .../de/blinkt/openvpn/activities/BaseActivity.java | 45 ----- .../de/blinkt/openvpn/activities/BaseActivity.kt | 81 ++++++++ .../blinkt/openvpn/activities/ConfigConverter.kt | 4 +- .../blinkt/openvpn/activities/InternalWebView.kt | 4 +- .../de/blinkt/openvpn/activities/LogWindow.java | 37 ---- .../java/de/blinkt/openvpn/activities/LogWindow.kt | 33 ++++ .../de/blinkt/openvpn/activities/MainActivity.kt | 11 +- .../de/blinkt/openvpn/activities/OpenSSLSpeed.kt | 1 + .../de/blinkt/openvpn/activities/VPNPreferences.kt | 9 +- .../de/blinkt/openvpn/fragments/AboutFragment.java | 13 ++ .../de/blinkt/openvpn/fragments/FaqFragment.java | 7 + .../de/blinkt/openvpn/fragments/LogFragment.java | 18 +- .../openvpn/fragments/Settings_Connections.kt | 4 - .../ui/java/de/blinkt/openvpn/fragments/Utils.kt | 39 +++- .../openvpn/views/ScreenSlidePagerAdapter.kt | 13 ++ main/src/ui/res/layout/about.xml | 1 + main/src/ui/res/layout/config_converter.xml | 204 +++++++++++---------- main/src/ui/res/layout/faq.xml | 20 +- main/src/ui/res/layout/log_fragment.xml | 1 + main/src/ui/res/layout/log_window.xml | 21 ++- main/src/ui/res/layout/main_activity.xml | 47 +++-- main/src/ui/res/layout/openssl_speed.xml | 72 ++++---- main/src/ui/res/layout/status_bg.xml | 5 + main/src/ui/res/layout/webview_internal.xml | 36 ++-- main/src/ui/res/values/styles.xml | 19 +- 25 files changed, 460 insertions(+), 285 deletions(-) delete mode 100644 main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.java create mode 100644 main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.kt delete mode 100644 main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.java create mode 100644 main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.kt create mode 100644 main/src/ui/res/layout/status_bg.xml (limited to 'main/src') diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.java b/main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.java deleted file mode 100644 index cca8b155..00000000 --- a/main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2012-2015 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.activities; - -import android.app.UiModeManager; -import android.content.Context; -import android.content.res.Configuration; -import android.os.Bundle; -import android.view.Window; - -import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; - -import de.blinkt.openvpn.core.LocaleHelper; - -public abstract class BaseActivity extends AppCompatActivity { - boolean isAndroidTV() { - final UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE); - if (uiModeManager == null) - return false; - return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - if (isAndroidTV()) { - requestWindowFeature(Window.FEATURE_OPTIONS_PANEL); - } - super.onCreate(savedInstanceState); - } - - @Override - protected void attachBaseContext(Context base) { - super.attachBaseContext(LocaleHelper.updateResources(base)); - } - - @Override - public void onConfigurationChanged(@NonNull Configuration newConfig) { - super.onConfigurationChanged(newConfig); - LocaleHelper.onConfigurationChange(this); - } -} diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.kt b/main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.kt new file mode 100644 index 00000000..9e6dd462 --- /dev/null +++ b/main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012-2015 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ +package de.blinkt.openvpn.activities + +import android.app.UiModeManager +import android.content.Context +import android.content.res.Configuration +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.view.Window +import androidx.activity.SystemBarStyle +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updateLayoutParams +import androidx.core.view.updatePadding +import de.blinkt.openvpn.R +import de.blinkt.openvpn.core.LocaleHelper + +abstract class BaseActivity : AppCompatActivity() { + val isAndroidTV: Boolean + get() { + val uiModeManager = getSystemService(UI_MODE_SERVICE) as UiModeManager + return uiModeManager.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION + } + + override fun onCreate(savedInstanceState: Bundle?) { + if (isAndroidTV) { + requestWindowFeature(Window.FEATURE_OPTIONS_PANEL) + } + this.enableEdgeToEdge(SystemBarStyle.dark(R.color.primary_dark)) + super.onCreate(savedInstanceState) + } + + fun setUpEdgeEdgeInsetsListener( + rootView: View, + contentViewId: Int = R.id.root_linear_layout, + setupBottom: Boolean = true + ) { + val contentView = rootView.findViewById(contentViewId) + + ViewCompat.setOnApplyWindowInsetsListener(contentView) { v, windowInsets -> + val insets = + windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()) + val statusbarbg = findViewById(R.id.statusbar_background); + + val statusBarInsets = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars()) + + statusbarbg.layoutParams.height = statusBarInsets.top + + + v.updateLayoutParams { + topMargin = insets.top + } + + v.updatePadding( + left = insets.left, + right = insets.right, + ) + if (setupBottom) { + v.updatePadding(bottom = insets.bottom) + WindowInsetsCompat.CONSUMED + } else { + windowInsets + } + } + } + + override fun attachBaseContext(base: Context) { + super.attachBaseContext(LocaleHelper.updateResources(base)) + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + LocaleHelper.onConfigurationChange(this) + } +} diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/ConfigConverter.kt b/main/src/ui/java/de/blinkt/openvpn/activities/ConfigConverter.kt index b85eaa26..a80afcab 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/ConfigConverter.kt +++ b/main/src/ui/java/de/blinkt/openvpn/activities/ConfigConverter.kt @@ -618,7 +618,9 @@ class ConfigConverter : BaseActivity(), FileSelectCallback, View.OnClickListener override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.config_converter) + val v = layoutInflater.inflate(R.layout.config_converter, null) + setUpEdgeEdgeInsetsListener(v, R.id.root_layout_config_converter) + setContentView(v) val fab_button = findViewById(R.id.fab_save) if (fab_button != null) { diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt b/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt index e46356e9..fec69768 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt +++ b/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt @@ -22,7 +22,7 @@ import de.blinkt.openvpn.R import de.blinkt.openvpn.VpnProfile import org.json.JSONObject -class InternalWebView : AppCompatActivity() { +class InternalWebView : BaseActivity() { lateinit var webView: WebView lateinit var urlTextView: TextView @@ -32,6 +32,8 @@ class InternalWebView : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.webview_internal) + setUpEdgeEdgeInsetsListener(getWindow().getDecorView().getRootView(), R.id.container) + webView = findViewById(R.id.internal_webview) urlTextView = findViewById(R.id.url_textview) diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.java b/main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.java deleted file mode 100644 index 5277a25d..00000000 --- a/main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2012-2016 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.activities; - -import android.app.Activity; -import android.os.Bundle; -import android.view.MenuItem; - -import de.blinkt.openvpn.R; -import de.blinkt.openvpn.fragments.LogFragment; - -/** - * Created by arne on 13.10.13. - */ -public class LogWindow extends BaseActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.log_window); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - if (savedInstanceState == null) { - getSupportFragmentManager().beginTransaction() - .add(R.id.container, new LogFragment()) - .commit(); - } - - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - return super.onOptionsItemSelected(item); - } -} diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.kt b/main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.kt new file mode 100644 index 00000000..afc18a03 --- /dev/null +++ b/main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012-2016 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ +package de.blinkt.openvpn.activities + +import android.os.Bundle +import android.view.MenuItem +import de.blinkt.openvpn.R +import de.blinkt.openvpn.fragments.LogFragment + +/** + * Created by arne on 13.10.13.setUpEdgeEdgeStuff + */ +class LogWindow : BaseActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.log_window) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + + if (savedInstanceState == null) { + supportFragmentManager.beginTransaction() + .add(R.id.container, LogFragment()) + .commit() + } + + setUpEdgeEdgeInsetsListener(getWindow().getDecorView().getRootView(), R.id.container) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return super.onOptionsItemSelected(item) + } +} diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/MainActivity.kt b/main/src/ui/java/de/blinkt/openvpn/activities/MainActivity.kt index 49778b88..a15de114 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/MainActivity.kt +++ b/main/src/ui/java/de/blinkt/openvpn/activities/MainActivity.kt @@ -10,7 +10,6 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.widget.Toast -import androidx.viewpager.widget.ViewPager import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator @@ -22,13 +21,14 @@ import de.blinkt.openvpn.views.ScreenSlidePagerAdapter class MainActivity : BaseActivity() { private lateinit var mPager: ViewPager2 private lateinit var mPagerAdapter: ScreenSlidePagerAdapter + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.main_activity) + val view = layoutInflater.inflate(R.layout.main_activity, null) // Instantiate a ViewPager and a PagerAdapter. - mPager = findViewById(R.id.pager) - val tablayout: TabLayout = findViewById(R.id.tab_layout) + mPager = view.findViewById(R.id.pager) + val tablayout: TabLayout = view.findViewById(R.id.tab_layout) mPagerAdapter = ScreenSlidePagerAdapter(supportFragmentManager, lifecycle, this) @@ -49,8 +49,11 @@ class MainActivity : BaseActivity() { tab.text = mPagerAdapter.getPageTitle(position) }.attach() + setUpEdgeEdgeInsetsListener(view, R.id.root_linear_layout) + setContentView(view) } + private fun disableToolbarElevation() { supportActionBar?.elevation = 0f } diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/OpenSSLSpeed.kt b/main/src/ui/java/de/blinkt/openvpn/activities/OpenSSLSpeed.kt index 324cd881..e7c6c2db 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/OpenSSLSpeed.kt +++ b/main/src/ui/java/de/blinkt/openvpn/activities/OpenSSLSpeed.kt @@ -105,6 +105,7 @@ class OpenSSLSpeed : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.openssl_speed) + setUpEdgeEdgeInsetsListener(getWindow().getDecorView().getRootView(), R.id.speed_root) supportActionBar!!.setDisplayHomeAsUpEnabled(true) findViewById(R.id.testSpecific).setOnClickListener { _ -> runAlgorithms(mCipher.text.toString()) } diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.kt b/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.kt index fd9fd43e..0dd61748 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.kt +++ b/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.kt @@ -104,13 +104,14 @@ class VPNPreferences : BaseActivity() { title = getString(R.string.edit_profile_title, mProfile!!.name) - setContentView(R.layout.main_activity) + val rootview = layoutInflater.inflate(R.layout.main_activity, null) + setUpEdgeEdgeInsetsListener(rootview, R.id.root_linear_layout) disableToolbarElevation() // Instantiate a ViewPager and a PagerAdapter. - mPager = findViewById(R.id.pager) - val tablayout: TabLayout = findViewById(R.id.tab_layout) + mPager = rootview.findViewById(R.id.pager) + val tablayout: TabLayout = rootview.findViewById(R.id.tab_layout) mPagerAdapter = ScreenSlidePagerAdapter(supportFragmentManager, lifecycle, this) @@ -143,6 +144,8 @@ class VPNPreferences : BaseActivity() { TabLayoutMediator(tablayout, mPager) { tab, position -> tab.text = mPagerAdapter.getPageTitle(position) }.attach() + + setContentView(rootview) } diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/AboutFragment.java b/main/src/ui/java/de/blinkt/openvpn/fragments/AboutFragment.java index de6c83d8..15375a3f 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/AboutFragment.java +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/AboutFragment.java @@ -27,6 +27,9 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import com.android.vending.billing.IInAppBillingService; @@ -108,6 +111,16 @@ public class AboutFragment extends Fragment implements View.OnClickListener { TextView wv = (TextView) v.findViewById(R.id.full_licenses); wv.setText(Html.fromHtml(readHtmlFromAssets())); + + + + ViewCompat.setOnApplyWindowInsetsListener(v, (view, windowInsets) -> + { + Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); + view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), insets.bottom); + return WindowInsetsCompat.CONSUMED; + } + ); return v; } diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/FaqFragment.java b/main/src/ui/java/de/blinkt/openvpn/fragments/FaqFragment.java index dcdfd5e3..2863b242 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/FaqFragment.java +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/FaqFragment.java @@ -9,6 +9,9 @@ import android.content.Context; import android.os.Build; import android.os.Bundle; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.StaggeredGridLayoutManager; @@ -196,9 +199,13 @@ public class FaqFragment extends Fragment { mRecyclerView.setAdapter(new FaqViewAdapter(getActivity(), getFAQEntries())); + Utils.applyInsetListener(v); + return v; } + + private FAQEntry[] getFAQEntries() { Vector faqItems = new Vector<>(); diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/LogFragment.java b/main/src/ui/java/de/blinkt/openvpn/fragments/LogFragment.java index 9ce65316..4a7cf735 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/LogFragment.java +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/LogFragment.java @@ -9,11 +9,9 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.app.Activity; -import android.app.PendingIntent; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.database.DataSetObserver; @@ -38,8 +36,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemLongClickListener; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.LinearLayout; @@ -631,16 +627,26 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar. }); if (mShowOptionsLayout) mOptionsLayout.setVisibility(View.VISIBLE); + +// ViewCompat.setOnApplyWindowInsetsListener(v, (view, windowInsets) -> +// { +// Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); +// view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), insets.bottom); +// return WindowInsetsCompat.CONSUMED; +// } +// ); + Utils.applyInsetListener(v); + return v; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - // Scroll to the end of the list end - //getListView().setSelection(getListView().getAdapter().getCount()-1); } + + @Override public void onAttach(@NonNull Context activity) { super.onAttach(activity); diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_Connections.kt b/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_Connections.kt index 8ed9d9ef..b06c3368 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_Connections.kt +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_Connections.kt @@ -40,12 +40,8 @@ class Settings_Connections : Settings_Fragment(), View.OnClickListener { val v = inflater.inflate(R.layout.connections, container, false) mWarning = v.findViewById(R.id.noserver_active_warning) as TextView mRecyclerView = v.findViewById(R.id.connection_recycler_view) as RecyclerView - val dpwidth = (container!!.width / resources.displayMetrics.density).toInt() - var columns = dpwidth / 290 - columns = 1.coerceAtLeast(columns) mConnectionsAdapter = ConnectionsAdapter(activity, this, mProfile) - //mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(columns, StaggeredGridLayoutManager.VERTICAL)); mRecyclerView.setHasFixedSize(true) mRecyclerView.layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false) diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/Utils.kt b/main/src/ui/java/de/blinkt/openvpn/fragments/Utils.kt index 55056424..e41dc337 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/Utils.kt +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/Utils.kt @@ -13,12 +13,14 @@ import android.os.Build import android.provider.OpenableColumns import android.text.SpannableString import android.text.SpannableStringBuilder -import android.text.TextUtils import android.text.style.ForegroundColorSpan import android.util.Base64 +import android.view.View import android.webkit.MimeTypeMap +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding import de.blinkt.openvpn.R -import kotlin.Throws import de.blinkt.openvpn.VpnProfile import de.blinkt.openvpn.core.Preferences import java.io.ByteArrayOutputStream @@ -319,4 +321,37 @@ object Utils { } } + @JvmStatic + fun applyInsetListener(v:View) + { + ViewCompat.setOnApplyWindowInsetsListener( + v + ) { view: View, windowInsets: WindowInsetsCompat -> + val insets = + windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()) + view.updatePadding( + bottom = insets.bottom + ) + WindowInsetsCompat.CONSUMED + } + v.requestApplyInsetsWhenAttached() + } +} + +fun View.requestApplyInsetsWhenAttached() { + if (isAttachedToWindow) { + // We're already attached, just request as normal + requestApplyInsets() + } else { + // We're not attached to the hierarchy, add a listener to + // request when we are + addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(v: View) { + v.removeOnAttachStateChangeListener(this) + v.requestApplyInsets() + } + + override fun onViewDetachedFromWindow(v: View) = Unit + }) + } } \ No newline at end of file diff --git a/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.kt b/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.kt index 0ce0afaa..98036953 100644 --- a/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.kt +++ b/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.kt @@ -7,11 +7,18 @@ package de.blinkt.openvpn.views import android.content.Context import android.content.res.Resources import android.os.Bundle +import android.view.View +import android.view.ViewGroup import androidx.annotation.StringRes +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updateLayoutParams +import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.lifecycle.Lifecycle import androidx.viewpager2.adapter.FragmentStateAdapter +import de.blinkt.openvpn.R import java.util.Vector /** @@ -31,11 +38,13 @@ class ScreenSlidePagerAdapter(fm: FragmentManager, lc: Lifecycle, c: Context) : internal class Tab(var fragmentClass: Class, var mName: String) private val mTabs = Vector() + private var mBottomPadding= 0 override fun createFragment(position: Int): Fragment { try { val fragment = mTabs[position].fragmentClass.newInstance() if (mFragmentArguments != null) fragment.arguments = mFragmentArguments + return fragment } catch (e: InstantiationException) { e.printStackTrace() @@ -56,4 +65,8 @@ class ScreenSlidePagerAdapter(fm: FragmentManager, lc: Lifecycle, c: Context) : fun addTab(@StringRes name: Int, fragmentClass: Class) { mTabs.add(Tab(fragmentClass, res.getString(name))) } + + fun setBottomPadding(bottom: Int) { + mBottomPadding = bottom; + } } diff --git a/main/src/ui/res/layout/about.xml b/main/src/ui/res/layout/about.xml index cd482996..f73768c7 100644 --- a/main/src/ui/res/layout/about.xml +++ b/main/src/ui/res/layout/about.xml @@ -9,6 +9,7 @@ android:layout_height="match_parent" android:paddingLeft="@dimen/stdpadding" android:paddingRight="@dimen/stdpadding" + android:clipToPadding="false" android:scrollbarStyle="outsideOverlay"> - - + android:layout_height="match_parent"> - - - - - - - - - - - - - - - - - - + android:orientation="vertical"> + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + - - + + diff --git a/main/src/ui/res/layout/faq.xml b/main/src/ui/res/layout/faq.xml index 8cb79649..46b56e58 100644 --- a/main/src/ui/res/layout/faq.xml +++ b/main/src/ui/res/layout/faq.xml @@ -1,15 +1,15 @@ - - \ No newline at end of file + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/faq_recycler_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clipToPadding="false" + android:horizontalSpacing="@dimen/stdpadding" + android:paddingLeft="@dimen/stdpadding" + android:paddingRight="@dimen/stdpadding" + android:verticalSpacing="@dimen/stdpadding" /> \ No newline at end of file diff --git a/main/src/ui/res/layout/log_fragment.xml b/main/src/ui/res/layout/log_fragment.xml index df87d1c1..bac1fe94 100644 --- a/main/src/ui/res/layout/log_fragment.xml +++ b/main/src/ui/res/layout/log_fragment.xml @@ -35,6 +35,7 @@ /> \ No newline at end of file + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:ignore="MergeRootFrame"> + + + + + + + \ No newline at end of file diff --git a/main/src/ui/res/layout/main_activity.xml b/main/src/ui/res/layout/main_activity.xml index edc64ece..6e0a3de9 100644 --- a/main/src/ui/res/layout/main_activity.xml +++ b/main/src/ui/res/layout/main_activity.xml @@ -2,29 +2,40 @@ ~ Copyright (c) 2012-2016 Arne Schwabe ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt --> - - + android:layout_height="match_parent"> - - /> - + + + + + + + - + \ No newline at end of file diff --git a/main/src/ui/res/layout/openssl_speed.xml b/main/src/ui/res/layout/openssl_speed.xml index c23d3567..d19b88d2 100644 --- a/main/src/ui/res/layout/openssl_speed.xml +++ b/main/src/ui/res/layout/openssl_speed.xml @@ -2,39 +2,47 @@ ~ Copyright (c) 2012-2017 Arne Schwabe ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt --> - - - - - - - -