]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
android: Expose managed configuration globally and notify listeners on changes
authorMarkus Pfeiffer <markus.pfeiffer@relution.io>
Tue, 21 Nov 2023 14:37:22 +0000 (15:37 +0100)
committerTobias Brunner <tobias@strongswan.org>
Wed, 21 Feb 2024 11:24:53 +0000 (12:24 +0100)
Triggers a broadcast if the configuration changed and updates the
profile list accordingly (previously only handled removal of multiple
profiles).

If the app resumes, the configuration is also loaded and listeners are
notified in case the config was updated while the app was in the
background.

src/frontends/android/app/build.gradle
src/frontends/android/app/src/main/java/org/strongswan/android/logic/StrongSwanApplication.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java

index 19542279179398ff4f4bbb5fa4203d7c667e0d54..2371347716fc3a8fb4f8edd4e4995b0795e5ff22 100644 (file)
@@ -45,6 +45,7 @@ android {
 
 dependencies {
     implementation 'androidx.appcompat:appcompat:1.6.1'
+    implementation 'androidx.lifecycle:lifecycle-process:2.7.0'
     implementation 'androidx.preference:preference:1.2.1'
     implementation 'com.google.android.material:material:1.10.0'
     testImplementation 'junit:junit:4.13.2'
index ac9866155e7bcf5ae81e347bd0d4aedd7f04a8c3..d3805a2844825d325f959d94c03333b40e96dc91 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2014 Tobias Brunner
+ * Copyright (C) 2023 Relution GmbH
+ * Copyright (C) 2014-2024 Tobias Brunner
  *
  * Copyright (C) secunet Security Networks AG
  *
 package org.strongswan.android.logic;
 
 import android.app.Application;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.Handler;
 import android.os.Looper;
+import android.util.Log;
 
+import org.strongswan.android.data.ManagedConfigurationService;
 import org.strongswan.android.security.LocalCertificateKeyStoreProvider;
+import org.strongswan.android.utils.Constants;
 
 import java.security.Security;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
+import androidx.annotation.NonNull;
 import androidx.core.os.HandlerCompat;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.ProcessLifecycleOwner;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 
-public class StrongSwanApplication extends Application
+public class StrongSwanApplication extends Application implements DefaultLifecycleObserver
 {
+       private static final String TAG = StrongSwanApplication.class.getSimpleName();
+
        private static Context mContext;
+
        private final ExecutorService mExecutorService = Executors.newFixedThreadPool(4);
        private final Handler mMainHandler = HandlerCompat.createAsync(Looper.getMainLooper());
 
+       private ManagedConfigurationService mManagedConfigurationService;
+
+       private final BroadcastReceiver mRestrictionsReceiver = new BroadcastReceiver()
+       {
+               @Override
+               public void onReceive(Context context, Intent intent)
+               {
+                       Log.d(TAG, "Managed configuration changed");
+                       reloadManagedConfigurationAndNotifyListeners();
+               }
+       };
+
        static
        {
                Security.addProvider(new LocalCertificateKeyStoreProvider());
@@ -46,6 +75,39 @@ public class StrongSwanApplication extends Application
        {
                super.onCreate();
                StrongSwanApplication.mContext = getApplicationContext();
+
+               mManagedConfigurationService = new ManagedConfigurationService(mContext);
+               ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
+       }
+
+       @Override
+       public void onResume(@NonNull LifecycleOwner owner)
+       {
+               reloadManagedConfigurationAndNotifyListeners();
+
+               final IntentFilter restrictionsFilter = new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
+               registerReceiver(mRestrictionsReceiver, restrictionsFilter);
+       }
+
+       @Override
+       public void onPause(@NonNull LifecycleOwner owner)
+       {
+               unregisterReceiver(mRestrictionsReceiver);
+       }
+
+       private void reloadManagedConfigurationAndNotifyListeners()
+       {
+               final Set<String> uuids = new HashSet<>(mManagedConfigurationService.getManagedProfiles().keySet());
+
+               mManagedConfigurationService.loadConfiguration();
+               mManagedConfigurationService.updateSettings();
+
+               uuids.addAll(mManagedConfigurationService.getManagedProfiles().keySet());
+
+               Log.d(TAG, "Send profiles changed broadcast");
+               Intent profilesChanged = new Intent(Constants.VPN_PROFILES_CHANGED);
+               profilesChanged.putExtra(Constants.VPN_PROFILES_MULTIPLE, uuids.toArray(new String[0]));
+               LocalBroadcastManager.getInstance(mContext).sendBroadcast(profilesChanged);
        }
 
        /**
@@ -78,6 +140,16 @@ public class StrongSwanApplication extends Application
                return mMainHandler;
        }
 
+       /**
+        * Returns a service providing access to the app's managed configuration.
+        *
+        * @return managed configuration
+        */
+       public ManagedConfigurationService getManagedConfigurationService()
+       {
+               return mManagedConfigurationService;
+       }
+
        /*
         * The libraries are extracted to /data/data/org.strongswan.android/...
         * during installation.  On newer releases most are loaded in JNI_OnLoad.
index c56962d72bf021f240a7ed4a4fe5c3b8969df970..051604f3e947c51134e4ae0de410a697ffc9fc16 100644 (file)
@@ -89,18 +89,24 @@ public class VpnProfileListFragment extends Fragment
                        }
                        else if ((uuids = intent.getStringArrayExtra(Constants.VPN_PROFILES_MULTIPLE)) != null)
                        {
-                               for (String id : uuids)
+                               for (final String id : uuids)
                                {
-                                       Iterator<VpnProfile> profiles = mVpnProfiles.iterator();
+                                       final Iterator<VpnProfile> profiles = mVpnProfiles.iterator();
                                        while (profiles.hasNext())
                                        {
-                                               VpnProfile profile = profiles.next();
+                                               final VpnProfile profile = profiles.next();
                                                if (Objects.equals(profile.getUUID().toString(), id))
-                                               {
+                                               {       /* in case this was an edit, we remove it first */
                                                        profiles.remove();
                                                        break;
                                                }
                                        }
+
+                                       VpnProfile profile = mDataSource.getVpnProfile(id);
+                                       if (profile != null)
+                                       {
+                                               mVpnProfiles.add(profile);
+                                       }
                                }
                                mListAdapter.notifyDataSetChanged();
                        }