]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
android: Apply UI changes for edge-to-edge views in Android 15+
authorTobias Brunner <tobias@strongswan.org>
Mon, 4 Aug 2025 12:35:11 +0000 (14:35 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 4 Aug 2025 13:48:29 +0000 (15:48 +0200)
When targeting Android 15, edge-to-edge is the default and when targeting
Android 16, apps can't opt-out from this anymore.  So we update our views
and enable edge-to-edge also for older versions (avoids the black bar
behind the system UI at the bottom).  For most views we just use automatic
margins via android:fitsSystemWindows (or programmatically via
setDecorFitsSystemWindows).  However, for the profile lists and log views,
we take some extra measures that allow the lists to go behind the bottom
system UI.  Appropriate padding is applied at the bottom of the lists so
the last item(s) can be scrolled into full view.

25 files changed:
src/frontends/android/app/build.gradle
src/frontends/android/app/src/main/AndroidManifest.xml
src/frontends/android/app/src/main/java/org/strongswan/android/ui/LogActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/LogFragment.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/MainActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/RemediationInstructionsActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/SelectedApplicationsActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/SettingsActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificateImportActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/TrustedCertificatesActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileDetailActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileImportActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileListFragment.java
src/frontends/android/app/src/main/java/org/strongswan/android/ui/VpnProfileSelectActivity.java
src/frontends/android/app/src/main/java/org/strongswan/android/utils/Utils.java
src/frontends/android/app/src/main/res/layout-large/remediation_instructions.xml
src/frontends/android/app/src/main/res/layout/log_activity.xml
src/frontends/android/app/src/main/res/layout/log_fragment.xml
src/frontends/android/app/src/main/res/layout/main.xml
src/frontends/android/app/src/main/res/layout/profile_detail_view.xml
src/frontends/android/app/src/main/res/layout/profile_import_view.xml
src/frontends/android/app/src/main/res/layout/profile_list_fragment.xml
src/frontends/android/app/src/main/res/layout/remediation_instructions.xml
src/frontends/android/app/src/main/res/layout/trusted_certificates_activity.xml
src/frontends/android/app/src/main/res/layout/vpn_profile_select.xml

index c9023aa9f8dcd8cc4accf754cd144a84922d89ae..f660312e0fd34cfb1e961ac9f718e21aad8e4b31 100644 (file)
@@ -46,6 +46,7 @@ android {
 
 dependencies {
     implementation 'androidx.appcompat:appcompat:1.7.1'
+    implementation 'androidx.core:core:1.17.0-rc01'
     implementation 'androidx.lifecycle:lifecycle-process:2.9.2'
     implementation 'androidx.preference:preference:1.2.1'
     implementation 'com.google.android.material:material:1.12.0'
index 51c6ff89e3d3af7b0d9e74db7575add1b50632b2..c0a8ed4840dd19e664276897f919559eba57266b 100644 (file)
@@ -36,6 +36,7 @@
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_name"
         android:theme="@style/ApplicationTheme"
+        android:windowSoftInputMode="adjustResize"
         android:networkSecurityConfig="@xml/network_security_config"
         android:enableOnBackInvokedCallback="true"
         android:allowBackup="false" >
index 40738fe6362545d14e78eae7ca8f3facf9ea77bc..c7d052ecdd517dd786803b6d4609d8ed5b1074cb 100644 (file)
@@ -26,10 +26,12 @@ import android.widget.Toast;
 import org.strongswan.android.R;
 import org.strongswan.android.data.LogContentProvider;
 import org.strongswan.android.logic.CharonVpnService;
+import org.strongswan.android.utils.Utils;
 
 import java.io.File;
 
 import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.view.WindowCompat;
 
 public class LogActivity extends AppCompatActivity
 {
@@ -38,6 +40,8 @@ public class LogActivity extends AppCompatActivity
        {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.log_activity);
+               WindowCompat.enableEdgeToEdge(getWindow());
+               Utils.applyWindowInsetsAsMarginsForLists(findViewById(R.id.layout));
 
                getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        }
index ca873a7fd805a118172907243aa0011ad21d953a..d83e1ec4a05afbb4c1acfd68f9bb752c62d34bf5 100644 (file)
@@ -30,6 +30,7 @@ import android.widget.ListView;
 
 import org.strongswan.android.R;
 import org.strongswan.android.logic.CharonVpnService;
+import org.strongswan.android.utils.Utils;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -81,6 +82,8 @@ public class LogFragment extends Fragment
                mLog = view.findViewById(R.id.log);
                mLog.setAdapter(mLogAdapter);
 
+               Utils.applyWindowInsetsAsPaddingForLists(mLog);
+
                mScrollPosition = -1;
                if (savedInstanceState != null)
                {
index 603dedef94c05e4bad2329f15c7c29011c0a4a1a..a1e647265c500705a2f5a5779b2b6f6caeedd8cd 100644 (file)
@@ -34,6 +34,7 @@ import org.strongswan.android.data.VpnProfile;
 import org.strongswan.android.logic.StrongSwanApplication;
 import org.strongswan.android.logic.TrustedCertificateManager;
 import org.strongswan.android.ui.VpnProfileListFragment.OnVpnProfileSelectedListener;
+import org.strongswan.android.utils.Utils;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -43,6 +44,7 @@ import androidx.appcompat.app.ActionBar;
 import androidx.appcompat.app.AlertDialog;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.app.AppCompatDialogFragment;
+import androidx.core.view.WindowCompat;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
 import androidx.fragment.app.FragmentTransaction;
@@ -66,6 +68,8 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec
        {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);
+               WindowCompat.enableEdgeToEdge(getWindow());
+               Utils.applyWindowInsetsAsMarginsForLists(findViewById(R.id.layout));
 
                ActionBar bar = getSupportActionBar();
                bar.setDisplayShowHomeEnabled(true);
index d1de552145ce2437d15a6e0e8b5657bc01458d27..3e8bd03b12880bc47c349c7ece77698e577d935d 100644 (file)
@@ -18,6 +18,8 @@ package org.strongswan.android.ui;
 
 import android.os.Bundle;
 import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.view.WindowCompat;
+
 import android.view.MenuItem;
 
 import org.strongswan.android.R;
@@ -33,6 +35,7 @@ public class RemediationInstructionsActivity extends AppCompatActivity implement
        {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.remediation_instructions);
+               WindowCompat.enableEdgeToEdge(getWindow());
                getSupportActionBar().setDisplayHomeAsUpEnabled(true);
 
                if (savedInstanceState != null)
index d1b66e4eea5d5b1c8eaca3ab66a5b85a1d3a46e7..b3c23ffc86333f2ad4765b56f72e7e1ff04b6a5f 100644 (file)
@@ -26,6 +26,7 @@ import androidx.activity.OnBackPressedCallback;
 import androidx.annotation.Nullable;
 import androidx.appcompat.app.ActionBar;
 import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.view.WindowCompat;
 import androidx.fragment.app.FragmentManager;
 
 public class SelectedApplicationsActivity extends AppCompatActivity
@@ -37,6 +38,8 @@ public class SelectedApplicationsActivity extends AppCompatActivity
        protected void onCreate(@Nullable Bundle savedInstanceState)
        {
                super.onCreate(savedInstanceState);
+               WindowCompat.enableEdgeToEdge(getWindow());
+               WindowCompat.setDecorFitsSystemWindows(getWindow(), true);
 
                ActionBar actionBar = getSupportActionBar();
                actionBar.setDisplayHomeAsUpEnabled(true);
index d1b5190e42f2a57428006b7ba086aa7f42b5986e..eec782fb71b994ac3faae153eded680cca03dcad 100644 (file)
@@ -20,6 +20,7 @@ import android.os.Bundle;
 import android.view.MenuItem;
 
 import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.view.WindowCompat;
 
 public class SettingsActivity extends AppCompatActivity
 {
@@ -28,6 +29,8 @@ public class SettingsActivity extends AppCompatActivity
        protected void onCreate(Bundle savedInstanceState)
        {
                super.onCreate(savedInstanceState);
+               WindowCompat.enableEdgeToEdge(getWindow());
+               WindowCompat.setDecorFitsSystemWindows(getWindow(), true);
 
                getSupportActionBar().setDisplayHomeAsUpEnabled(true);
 
index 322e21e2c0ab93010c37424f6d4a23e5073cf915..a794e93bae720b7ba28b349bda870eeff2b61836 100644 (file)
@@ -41,6 +41,7 @@ import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.appcompat.app.AlertDialog;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.app.AppCompatDialogFragment;
+import androidx.core.view.WindowCompat;
 import androidx.fragment.app.FragmentTransaction;
 
 public class TrustedCertificateImportActivity extends AppCompatActivity
index 0a0b26a8a46273914f56f6a12ff8bda3e1e36404..c9e24288103db5e5ef206c54feb96b19e032eaf4 100644 (file)
@@ -33,6 +33,7 @@ import org.strongswan.android.logic.TrustedCertificateManager;
 import org.strongswan.android.logic.TrustedCertificateManager.TrustedCertificateSource;
 import org.strongswan.android.security.TrustedCertificateEntry;
 import org.strongswan.android.ui.CertificateDeleteConfirmationDialog.OnCertificateDeleteListener;
+import org.strongswan.android.utils.Utils;
 
 import java.security.KeyStore;
 
@@ -41,6 +42,7 @@ import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.annotation.NonNull;
 import androidx.appcompat.app.ActionBar;
 import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.view.WindowCompat;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentActivity;
 import androidx.viewpager2.adapter.FragmentStateAdapter;
@@ -71,6 +73,7 @@ public class TrustedCertificatesActivity extends AppCompatActivity implements Tr
        {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.trusted_certificates_activity);
+               WindowCompat.enableEdgeToEdge(getWindow());
 
                ActionBar actionBar = getSupportActionBar();
                actionBar.setDisplayHomeAsUpEnabled(true);
index cf1789d4b9bf8a23d8c69b844aebb292d9025780..13e38273e6c48556e5f8d195eefccfcc757cda17 100644 (file)
@@ -84,6 +84,7 @@ import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.app.AppCompatDialogFragment;
 import androidx.appcompat.widget.SwitchCompat;
 import androidx.core.text.HtmlCompat;
+import androidx.core.view.WindowCompat;
 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 
 public class VpnProfileDetailActivity extends AppCompatActivity
@@ -199,6 +200,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity
                mDataSource.open();
 
                setContentView(R.layout.profile_detail_view);
+               WindowCompat.enableEdgeToEdge(getWindow());
 
                mManagedProfile = findViewById(R.id.managed_profile);
 
index ee56c1e5301e5c1bed00355c1ad5dae627bf37f9..f10ce0e14bbe9cb24d92904e9e3e265391c73562 100644 (file)
@@ -78,6 +78,7 @@ import javax.net.ssl.SSLHandshakeException;
 import androidx.activity.result.ActivityResultLauncher;
 import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.view.WindowCompat;
 import androidx.loader.app.LoaderManager;
 import androidx.loader.content.AsyncTaskLoader;
 import androidx.loader.content.Loader;
@@ -204,6 +205,7 @@ public class VpnProfileImportActivity extends AppCompatActivity
                mDataSource.open();
 
                setContentView(R.layout.profile_import_view);
+               WindowCompat.enableEdgeToEdge(getWindow());
 
                mProgressBar = findViewById(R.id.progress_bar);
                mExistsWarning = findViewById(R.id.exists_warning);
index 1679ef5bd3962b4515e306b0ea1dce89d1587b2e..e845cc65981b38c538e207f72c27b857507e15aa 100644 (file)
@@ -48,6 +48,7 @@ import org.strongswan.android.data.VpnProfileSource;
 import org.strongswan.android.logic.StrongSwanApplication;
 import org.strongswan.android.ui.adapter.VpnProfileAdapter;
 import org.strongswan.android.utils.Constants;
+import org.strongswan.android.utils.Utils;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -148,6 +149,8 @@ public class VpnProfileListFragment extends Fragment implements MenuProvider
                mListView.setEmptyView(view.findViewById(R.id.profile_list_empty));
                mListView.setOnItemClickListener(mVpnProfileClicked);
 
+               Utils.applyWindowInsetsAsPaddingForLists(mListView);
+
                if (!mReadOnly)
                {
                        requireActivity().addMenuProvider(this, getViewLifecycleOwner());
index dd64d0c7592cabed412fd535519425e6a2881862..56aefbede6ce47d6ba73c58592af7ab064b156ae 100644 (file)
@@ -22,11 +22,13 @@ import android.os.Bundle;
 import org.strongswan.android.R;
 import org.strongswan.android.data.VpnProfile;
 import org.strongswan.android.ui.VpnProfileListFragment.OnVpnProfileSelectedListener;
+import org.strongswan.android.utils.Utils;
 
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.core.content.pm.ShortcutInfoCompat;
 import androidx.core.content.pm.ShortcutManagerCompat;
 import androidx.core.graphics.drawable.IconCompat;
+import androidx.core.view.WindowCompat;
 
 public class VpnProfileSelectActivity extends AppCompatActivity implements OnVpnProfileSelectedListener
 {
@@ -35,6 +37,8 @@ public class VpnProfileSelectActivity extends AppCompatActivity implements OnVpn
        {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.vpn_profile_select);
+               WindowCompat.enableEdgeToEdge(getWindow());
+               Utils.applyWindowInsetsAsMarginsForLists(findViewById(R.id.layout));
 
                /* we should probably return a result also if the user clicks the back
                 * button before selecting a profile */
index 5142ee1b59269b6248c3447d0ef39b05bb575982..ac1a315c4425e1ede4095f187cd7c1d5e1087bbc 100644 (file)
 package org.strongswan.android.utils;
 
 
+import android.view.View;
+import android.view.ViewGroup;
+
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+
 public class Utils
 {
        static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
@@ -75,4 +82,39 @@ public class Utils
                }
                return InetAddress.getByAddress(bytes);
        }
+
+       /**
+        * Apply window insets for the system UI as margins except for the bottom,
+        * which is useful if the view ends with a list. WindowInsetsCompat.CONSUMED
+        * is not returned so padding can be applied to the list.
+        *
+        * @param view view to apply margins to
+        */
+       public static void applyWindowInsetsAsMarginsForLists(View view)
+       {
+               ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
+                       Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
+                       ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)v.getLayoutParams();
+                       mlp.topMargin = insets.top;
+                       mlp.leftMargin = insets.left;
+                       mlp.rightMargin = insets.right;
+                       v.setLayoutParams(mlp);
+                       return windowInsets;
+               });
+       }
+
+       /**
+        * Apply bottom inset for the system UI as padding on the given (list) view
+        * so the last item can be scrolled fully into view.
+        *
+        * @param view view to apply padding to
+        */
+       public static void applyWindowInsetsAsPaddingForLists(View view)
+       {
+               ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
+                       Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
+                       v.setPaddingRelative(0, 0, 0, insets.bottom);
+                       return WindowInsetsCompat.CONSUMED;
+               });
+       }
 }
index 1c6494f6e164071bb67b4912f88f93d96ee399d7..a2db35116fc60e3f318d89bb3ff30bceeb9a1026 100644 (file)
@@ -18,7 +18,8 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="horizontal"
-    android:baselineAligned="false" >
+    android:baselineAligned="false"
+    android:fitsSystemWindows="true" >
 
     <fragment
         class="org.strongswan.android.ui.RemediationInstructionsFragment"
index 7f85456f39533becb2d7eec893366e0f433fe434..7a1fe3bf22a409d300faef3c1b09dd511698d31e 100644 (file)
@@ -16,7 +16,8 @@
 -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent" >
+    android:layout_height="match_parent"
+    android:id="@+id/layout" >
 
     <fragment
             class="org.strongswan.android.ui.LogFragment"
index b305b4de0ae146fa39826d7b84f79c572025bc5c..a707054f0744b66c9f3bf8dfc9d0833b80a4725f 100644 (file)
     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     for more details.
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical" >
+    android:paddingBottom="0dp"
+    android:paddingTop="5dp"
+    android:paddingStart="5dp"
+    android:paddingEnd="5dp" >
 
     <ListView
         android:id="@+id/log"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_margin="10dp"
         android:dividerHeight="0dp"
         android:divider="@null"
         android:fadeScrollbars="false"
         android:scrollbarFadeDuration="0"
         android:scrollbarAlwaysDrawVerticalTrack="true"
-        android:transcriptMode="normal">
+        android:transcriptMode="normal"
+        android:clipToPadding="false" />
 
-    </ListView>
-
-</LinearLayout>
+</FrameLayout>
index 2aaf181b2aaa0bf14b04d27e411832fe1c7e2e12..06932866f2fbc440da90421e2be4b361538dfbd7 100644 (file)
@@ -17,7 +17,8 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical" >
+    android:orientation="vertical"
+    android:id="@+id/layout" >
 
     <fragment
             class="org.strongswan.android.ui.VpnStateFragment"
index 04696058b66e8ac7a8bde486a4eefd38fc669dd4..878514e768fa843a556d816b598af47959005880 100644 (file)
@@ -20,7 +20,8 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true">
 
     <TextView
         android:id="@+id/managed_profile"
index 231b552c930ea91b2cb294b8edefaf57ce868788..f6cbf2c2d0e3cd4b2c95355833638ed5dde1b635 100644 (file)
     for more details.
 -->
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-            xmlns:app="http://schemas.android.com/apk/res-auto"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" >
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true" >
 
     <LinearLayout
         android:layout_width="match_parent"
index 6cc9d5b9c70ac4d6ea3b436eb5909c737c398d67..9878147f53d4b9a0e58164065605b92bc6df1726 100644 (file)
@@ -17,7 +17,7 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:paddingBottom="10dp"
+    android:paddingBottom="0dp"
     android:paddingTop="10dp"
     android:paddingStart="5dp"
     android:paddingEnd="5dp" >
         android:layout_height="match_parent"
         android:dividerHeight="1dp"
         android:divider="?android:attr/listDivider"
-        android:scrollbarAlwaysDrawVerticalTrack="true" />
+        android:overScrollFooter="@android:color/transparent"
+        android:scrollbarAlwaysDrawVerticalTrack="true"
+        android:clipToPadding="false" />
 
-     <TextView android:id="@+id/profile_list_empty"
+    <TextView android:id="@+id/profile_list_empty"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_marginStart="15dp"
index c23f982ecae550f106a7e792e08dc3c300b58f18..5b3f644b9de5fb06883d64550d648a8c4827ff83 100644 (file)
@@ -17,6 +17,7 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:id="@+id/fragment_container">
 
-</FrameLayout>
\ No newline at end of file
+</FrameLayout>
index 1eee0590df0597301ff6632bd42e2fd24a985601..ee7ec19013e4aaae31597a32f4622e515f34a624 100644 (file)
     for more details.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:app="http://schemas.android.com/apk/res-auto"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:fitsSystemWindows="true">
 
     <com.google.android.material.tabs.TabLayout
         android:id="@+id/tabs"
index b7fbb6630ff45dc849426f68c8ca9fea3541ffeb..6db6041e4f820f72453187a320f6ea0e12f8e177 100644 (file)
@@ -18,7 +18,8 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical" >
+    android:orientation="vertical"
+    android:id="@+id/layout" >
 
     <fragment
             class="org.strongswan.android.ui.VpnProfileListFragment"
@@ -28,4 +29,4 @@
             android:layout_weight="1"
             app:read_only="true" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>