From 6039cfa20e024f0059d5e206cdf686fa8447e0d1 Mon Sep 17 00:00:00 2001 From: cillyvms Date: Tue, 26 Nov 2024 01:05:20 +0100 Subject: [PATCH] Apply window insets to prevent UI elements from going behind system windows. --- .../aegis/helpers/ViewHelper.java | 26 +++++++++++++++++++ .../aegis/ui/AboutActivity.java | 16 ++++++++++++ .../aegis/ui/AssignIconsActivity.java | 2 ++ .../aegis/ui/EditEntryActivity.java | 2 ++ .../aegis/ui/GroupManagerActivity.java | 2 ++ .../aegis/ui/ImportEntriesActivity.java | 2 ++ .../aegis/ui/MainActivity.java | 2 ++ .../aegis/ui/PreferencesActivity.java | 2 ++ .../aegis/ui/ScannerActivity.java | 2 ++ .../aegis/ui/TransferEntriesActivity.java | 2 ++ .../AuditLogPreferencesFragment.java | 14 ++++++++++ .../preferences/IconPacksManagerFragment.java | 17 ++++++++++++ .../preferences/PreferencesFragment.java | 24 +++++++++++++++++ .../aegis/ui/views/EntryListView.java | 20 ++++++++++++++ app/src/main/res/layout/activity_about.xml | 1 + .../main/res/layout/fragment_audit_log.xml | 1 + .../res/layout/fragment_entry_list_view.xml | 1 + 17 files changed, 136 insertions(+) create mode 100644 app/src/main/java/com/beemdevelopment/aegis/helpers/ViewHelper.java diff --git a/app/src/main/java/com/beemdevelopment/aegis/helpers/ViewHelper.java b/app/src/main/java/com/beemdevelopment/aegis/helpers/ViewHelper.java new file mode 100644 index 00000000..910aae2f --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/helpers/ViewHelper.java @@ -0,0 +1,26 @@ +package com.beemdevelopment.aegis.helpers; + +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; + +import com.google.android.material.appbar.AppBarLayout; + +public class ViewHelper { + private ViewHelper() { + + } + + public static void setupAppBarInsets(AppBarLayout appBar) { + ViewCompat.setOnApplyWindowInsetsListener(appBar, (targetView, windowInsets) -> { + Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); + targetView.setPadding( + insets.left, + insets.top, + insets.right, + 0 + ); + return WindowInsetsCompat.CONSUMED; + }); + } +} diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/AboutActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/AboutActivity.java index c9eee550..4b974b68 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/AboutActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/AboutActivity.java @@ -13,11 +13,15 @@ import android.widget.Toast; import androidx.annotation.AttrRes; import androidx.annotation.StringRes; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import com.beemdevelopment.aegis.BuildConfig; import com.beemdevelopment.aegis.R; import com.beemdevelopment.aegis.ui.dialogs.ChangelogDialog; import com.beemdevelopment.aegis.ui.dialogs.LicenseDialog; +import com.beemdevelopment.aegis.helpers.ViewHelper; import com.google.android.material.color.MaterialColors; public class AboutActivity extends AegisActivity { @@ -39,6 +43,7 @@ public class AboutActivity extends AegisActivity { setContentView(R.layout.activity_about); setSupportActionBar(findViewById(R.id.toolbar)); + ViewHelper.setupAppBarInsets(findViewById(R.id.app_bar_layout)); if (getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -90,6 +95,17 @@ public class AboutActivity extends AegisActivity { .setTheme(_themeHelper.getConfiguredTheme()) .show(getSupportFragmentManager(), null); }); + + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.about_scroll_view), (targetView, windowInsets) -> { + Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); + targetView.setPadding( + 0, + 0, + 0, + insets.bottom + ); + return WindowInsetsCompat.CONSUMED; + }); } private static String getCurrentAppVersion() { diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/AssignIconsActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/AssignIconsActivity.java index f049f70d..024f9200 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/AssignIconsActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/AssignIconsActivity.java @@ -25,6 +25,7 @@ import com.beemdevelopment.aegis.ui.models.AssignIconEntry; import com.beemdevelopment.aegis.ui.views.AssignIconAdapter; import com.beemdevelopment.aegis.ui.views.IconAdapter; import com.beemdevelopment.aegis.util.IOUtils; +import com.beemdevelopment.aegis.helpers.ViewHelper; import com.beemdevelopment.aegis.vault.VaultEntry; import com.beemdevelopment.aegis.vault.VaultEntryIcon; import com.bumptech.glide.Glide; @@ -61,6 +62,7 @@ public class AssignIconsActivity extends AegisActivity implements AssignIconAdap setContentView(R.layout.activity_assign_icons); setSupportActionBar(findViewById(R.id.toolbar)); + ViewHelper.setupAppBarInsets(findViewById(R.id.app_bar_layout)); if (getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java index 68f3db7a..086559de 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java @@ -59,6 +59,7 @@ import com.beemdevelopment.aegis.ui.tasks.ImportFileTask; import com.beemdevelopment.aegis.ui.views.IconAdapter; import com.beemdevelopment.aegis.util.Cloner; import com.beemdevelopment.aegis.util.IOUtils; +import com.beemdevelopment.aegis.helpers.ViewHelper; import com.beemdevelopment.aegis.vault.VaultEntry; import com.beemdevelopment.aegis.vault.VaultEntryIcon; import com.beemdevelopment.aegis.vault.VaultGroup; @@ -164,6 +165,7 @@ public class EditEntryActivity extends AegisActivity { } setContentView(R.layout.activity_edit_entry); setSupportActionBar(findViewById(R.id.toolbar)); + ViewHelper.setupAppBarInsets(findViewById(R.id.app_bar_layout)); _groups = _vaultManager.getVault().getGroups(); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/GroupManagerActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/GroupManagerActivity.java index b2872e72..4c29dea2 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/GroupManagerActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/GroupManagerActivity.java @@ -15,6 +15,7 @@ import com.beemdevelopment.aegis.R; import com.beemdevelopment.aegis.ui.dialogs.Dialogs; import com.beemdevelopment.aegis.ui.views.GroupAdapter; import com.beemdevelopment.aegis.util.Cloner; +import com.beemdevelopment.aegis.helpers.ViewHelper; import com.beemdevelopment.aegis.vault.VaultGroup; import com.google.android.material.dialog.MaterialAlertDialogBuilder; @@ -39,6 +40,7 @@ public class GroupManagerActivity extends AegisActivity implements GroupAdapter. } setContentView(R.layout.activity_groups); setSupportActionBar(findViewById(R.id.toolbar)); + ViewHelper.setupAppBarInsets(findViewById(R.id.app_bar_layout)); if (getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/ImportEntriesActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/ImportEntriesActivity.java index 54cf675e..0bf70b36 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/ImportEntriesActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/ImportEntriesActivity.java @@ -24,6 +24,7 @@ import com.beemdevelopment.aegis.ui.models.ImportEntry; import com.beemdevelopment.aegis.ui.tasks.RootShellTask; import com.beemdevelopment.aegis.ui.views.ImportEntriesAdapter; import com.beemdevelopment.aegis.util.UUIDMap; +import com.beemdevelopment.aegis.helpers.ViewHelper; import com.beemdevelopment.aegis.vault.VaultEntry; import com.beemdevelopment.aegis.vault.VaultGroup; import com.beemdevelopment.aegis.vault.VaultRepository; @@ -58,6 +59,7 @@ public class ImportEntriesActivity extends AegisActivity { } setContentView(R.layout.activity_import_entries); setSupportActionBar(findViewById(R.id.toolbar)); + ViewHelper.setupAppBarInsets(findViewById(R.id.app_bar_layout)); _view = findViewById(R.id.importEntriesRootView); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java index 97102017..13d82f66 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -59,6 +59,7 @@ import com.beemdevelopment.aegis.ui.tasks.QrDecodeTask; import com.beemdevelopment.aegis.ui.views.EntryListView; import com.beemdevelopment.aegis.util.TimeUtils; import com.beemdevelopment.aegis.util.UUIDMap; +import com.beemdevelopment.aegis.helpers.ViewHelper; import com.beemdevelopment.aegis.vault.VaultEntry; import com.beemdevelopment.aegis.vault.VaultFile; import com.beemdevelopment.aegis.vault.VaultGroup; @@ -183,6 +184,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setSupportActionBar(findViewById(R.id.toolbar)); + ViewHelper.setupAppBarInsets(findViewById(R.id.app_bar_layout)); _loaded = false; _isDPadPressed = false; _isDoingIntro = false; diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesActivity.java index e4d55919..1e7dff67 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesActivity.java @@ -13,6 +13,7 @@ import com.beemdevelopment.aegis.R; import com.beemdevelopment.aegis.ui.fragments.preferences.AppearancePreferencesFragment; import com.beemdevelopment.aegis.ui.fragments.preferences.MainPreferencesFragment; import com.beemdevelopment.aegis.ui.fragments.preferences.PreferencesFragment; +import com.beemdevelopment.aegis.helpers.ViewHelper; public class PreferencesActivity extends AegisActivity implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { @@ -27,6 +28,7 @@ public class PreferencesActivity extends AegisActivity implements } setContentView(R.layout.activity_preferences); setSupportActionBar(findViewById(R.id.toolbar)); + ViewHelper.setupAppBarInsets(findViewById(R.id.app_bar_layout)); getSupportFragmentManager() .registerFragmentLifecycleCallbacks(new FragmentResumeListener(), true); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/ScannerActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/ScannerActivity.java index e98a2ca3..cc0d6095 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/ScannerActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/ScannerActivity.java @@ -22,6 +22,7 @@ import com.beemdevelopment.aegis.helpers.QrCodeAnalyzer; import com.beemdevelopment.aegis.otp.GoogleAuthInfo; import com.beemdevelopment.aegis.otp.GoogleAuthInfoException; import com.beemdevelopment.aegis.ui.dialogs.Dialogs; +import com.beemdevelopment.aegis.helpers.ViewHelper; import com.beemdevelopment.aegis.vault.VaultEntry; import com.google.common.util.concurrent.ListenableFuture; import com.google.zxing.Result; @@ -56,6 +57,7 @@ public class ScannerActivity extends AegisActivity implements QrCodeAnalyzer.Lis } setContentView(R.layout.activity_scanner); setSupportActionBar(findViewById(R.id.toolbar)); + ViewHelper.setupAppBarInsets(findViewById(R.id.app_bar_layout)); _entries = new ArrayList<>(); _lenses = new ArrayList<>(); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/TransferEntriesActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/TransferEntriesActivity.java index a0e81849..a4deae57 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/TransferEntriesActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/TransferEntriesActivity.java @@ -28,6 +28,7 @@ import com.beemdevelopment.aegis.otp.GoogleAuthInfo; import com.beemdevelopment.aegis.otp.GoogleAuthInfoException; import com.beemdevelopment.aegis.otp.Transferable; import com.beemdevelopment.aegis.ui.dialogs.Dialogs; +import com.beemdevelopment.aegis.helpers.ViewHelper; import com.google.android.material.color.MaterialColors; import com.google.android.material.imageview.ShapeableImageView; import com.google.zxing.WriterException; @@ -55,6 +56,7 @@ public class TransferEntriesActivity extends AegisActivity { } setContentView(R.layout.activity_share_entry); setSupportActionBar(findViewById(R.id.toolbar)); + ViewHelper.setupAppBarInsets(findViewById(R.id.app_bar_layout)); _qrImage = findViewById(R.id.ivQrCode); _description = findViewById(R.id.tvDescription); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AuditLogPreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AuditLogPreferencesFragment.java index daa722a8..8199dfa1 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AuditLogPreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/AuditLogPreferencesFragment.java @@ -6,6 +6,9 @@ import android.view.View; import android.widget.LinearLayout; import androidx.annotation.NonNull; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.LiveData; import androidx.recyclerview.widget.LinearLayoutManager; @@ -58,6 +61,17 @@ public class AuditLogPreferencesFragment extends Fragment { _auditLogRecyclerView.setAdapter(_adapter); _auditLogRecyclerView.setNestedScrollingEnabled(false); + ViewCompat.setOnApplyWindowInsetsListener(_auditLogRecyclerView, (targetView, windowInsets) -> { + Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); + targetView.setPadding( + 0, + 0, + 0, + insets.bottom + ); + return WindowInsetsCompat.CONSUMED; + }); + entries.observe(getViewLifecycleOwner(), entries1 -> { _noAuditLogsView.setVisibility(entries1.isEmpty() ? View.VISIBLE : View.GONE); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/IconPacksManagerFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/IconPacksManagerFragment.java index 0b23328e..a95713a1 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/IconPacksManagerFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/IconPacksManagerFragment.java @@ -6,6 +6,7 @@ import android.net.Uri; import android.os.Bundle; import android.text.method.LinkMovementMethod; import android.view.View; +import android.view.ViewGroup.MarginLayoutParams; import android.view.animation.Animation; import android.widget.LinearLayout; import android.widget.TextView; @@ -14,6 +15,9 @@ import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -67,6 +71,19 @@ public class IconPacksManagerFragment extends Fragment implements IconPackAdapte fab.setOnClickListener(v -> startImportIconPack()); _fabScrollHelper = new FabScrollHelper(fab); + final MarginLayoutParams fabInitialMargin = (MarginLayoutParams) fab.getLayoutParams(); + ViewCompat.setOnApplyWindowInsetsListener(fab, (targetView, windowInsets) -> { + Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); + + MarginLayoutParams marginParams = (MarginLayoutParams) targetView.getLayoutParams(); + marginParams.leftMargin = fabInitialMargin.leftMargin + insets.left; + marginParams.bottomMargin = fabInitialMargin.bottomMargin + insets.bottom; + marginParams.rightMargin = fabInitialMargin.rightMargin + insets.right; + targetView.setLayoutParams(marginParams); + + return WindowInsetsCompat.CONSUMED; + }); + _noIconPacksView = view.findViewById(R.id.vEmptyList); ((TextView) view.findViewById(R.id.txt_no_icon_packs)).setMovementMethod(LinkMovementMethod.getInstance()); _adapter = new IconPackAdapter(this); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/PreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/PreferencesFragment.java index 367c32e1..63069160 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/PreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/fragments/preferences/PreferencesFragment.java @@ -1,13 +1,20 @@ package com.beemdevelopment.aegis.ui.fragments.preferences; import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.ViewGroup; import android.view.animation.Animation; import androidx.annotation.CallSuper; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; +import androidx.recyclerview.widget.RecyclerView; import com.beemdevelopment.aegis.Preferences; import com.beemdevelopment.aegis.R; @@ -61,6 +68,23 @@ public abstract class PreferencesFragment extends PreferenceFragmentCompat { return super.onCreateAnimation(transit, enter, nextAnim); } + @NonNull + @Override + public RecyclerView onCreateRecyclerView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent, @Nullable Bundle savedInstanceState) { + RecyclerView recyclerView = super.onCreateRecyclerView(inflater, parent, savedInstanceState); + ViewCompat.setOnApplyWindowInsetsListener(recyclerView, (targetView, windowInsets) -> { + Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); + targetView.setPadding( + 0, + 0, + 0, + insets.bottom + ); + return WindowInsetsCompat.CONSUMED; + }); + return recyclerView; + } + protected boolean saveAndBackupVault() { try { _vaultManager.saveAndBackup(); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java index 500198c0..3d359290 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/EntryListView.java @@ -19,6 +19,9 @@ import androidx.annotation.AttrRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StyleRes; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.ItemTouchHelper; @@ -149,6 +152,23 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener { } }); + final int rvInitialPaddingLeft = _recyclerView.getPaddingLeft(); + final int rvInitialPaddingTop = _recyclerView.getPaddingTop(); + final int rvInitialPaddingRight = _recyclerView.getPaddingRight(); + final int rvInitialPaddingBottom = _recyclerView.getPaddingBottom(); + + ViewCompat.setOnApplyWindowInsetsListener(_recyclerView, (targetView, windowInsets) -> { + Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); + // left and right padding seems to be handled by fitsSystemWindows="true" on the CoordinatorLayout in activity_main.xml + targetView.setPadding( + rvInitialPaddingLeft, + rvInitialPaddingTop, + rvInitialPaddingRight, + rvInitialPaddingBottom + insets.bottom + ); + return WindowInsetsCompat.CONSUMED; + }); + _emptyStateView = view.findViewById(R.id.vEmptyList); return view; } diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index 280d52d5..d4b17d0b 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -17,6 +17,7 @@ android:layout_height="?attr/actionBarSize" /> diff --git a/app/src/main/res/layout/fragment_entry_list_view.xml b/app/src/main/res/layout/fragment_entry_list_view.xml index eaacfb4b..4f4fc0e3 100644 --- a/app/src/main/res/layout/fragment_entry_list_view.xml +++ b/app/src/main/res/layout/fragment_entry_list_view.xml @@ -20,6 +20,7 @@ android:paddingHorizontal="8dp" android:scrollbars="vertical" android:scrollbarStyle="outsideOverlay" + android:clipToPadding="false" android:id="@+id/rvKeyProfiles" android:layout_weight="1"/>