From: Markus Pfeiffer Date: Tue, 21 Nov 2023 14:37:22 +0000 (+0100) Subject: android: Expose managed configuration globally and notify listeners on changes X-Git-Tag: android-2.5.0^2~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=36f62585bbd8d7ec5781711269b9184bc5193e5b;p=thirdparty%2Fstrongswan.git android: Expose managed configuration globally and notify listeners on changes 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. --- diff --git a/src/frontends/android/app/build.gradle b/src/frontends/android/app/build.gradle index 1954227917..2371347716 100644 --- a/src/frontends/android/app/build.gradle +++ b/src/frontends/android/app/build.gradle @@ -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' diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/StrongSwanApplication.java b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/StrongSwanApplication.java index ac9866155e..d3805a2844 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/logic/StrongSwanApplication.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/logic/StrongSwanApplication.java @@ -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 * @@ -17,25 +18,53 @@ 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 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. diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java index c56962d72b..051604f3e9 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java @@ -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 profiles = mVpnProfiles.iterator(); + final Iterator 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(); }