diff --git a/app/build.gradle b/app/build.gradle index 1b7b9f97e8cc..751cd560af91 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -116,8 +116,8 @@ android { defaultConfig { applicationId = "com.nextcloud.client" minSdk = 27 - targetSdk = 35 - compileSdk = 35 + targetSdk = 36 + compileSdk = 36 buildConfigField "boolean", "CI", ciBuild.toString() buildConfigField "boolean", "RUNTIME_PERF_ANALYSIS", perfAnalysis.toString() diff --git a/app/src/androidTest/java/com/owncloud/android/ui/activity/FileDisplayActivityTest.java b/app/src/androidTest/java/com/owncloud/android/ui/activity/FileDisplayActivityTest.java index c9ec5e04ad73..8f65ddcd8517 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/activity/FileDisplayActivityTest.java +++ b/app/src/androidTest/java/com/owncloud/android/ui/activity/FileDisplayActivityTest.java @@ -27,8 +27,8 @@ public void testSetupToolbar() { InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { Activity activity = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(RESUMED).iterator().next(); - if (activity instanceof WhatsNewActivity) { - activity.onBackPressed(); + if (activity instanceof WhatsNewActivity whatsNewActivity) { + whatsNewActivity.getOnBackPressedDispatcher().onBackPressed(); } }); scenario.recreate(); diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt index 7fa76a889add..77c204eb31c0 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/FileDetailSharingFragmentIT.kt @@ -822,7 +822,7 @@ class FileDetailSharingFragmentIT : AbstractIT() { val processFragment = activity.supportFragmentManager.findFragmentByTag(FileDetailsSharingProcessFragment.TAG) as FileDetailsSharingProcessFragment - processFragment.onBackPressed() + processFragment.activity?.onBackPressedDispatcher?.onBackPressed() } } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8331fb591ae1..1ca3e4966c69 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -121,7 +121,7 @@ android:requestLegacyExternalStorage="true" android:roundIcon="@mipmap/ic_launcher" android:supportsRtl="true" - android:enableOnBackInvokedCallback="false" + android:enableOnBackInvokedCallback="true" android:theme="@style/Theme.ownCloud.Toolbar" android:usesCleartextTraffic="true" tools:ignore="UnusedAttribute" @@ -353,6 +353,7 @@ { - onBackPressed() + onBackPressedDispatcher.onBackPressed() true } else -> false diff --git a/app/src/main/java/com/nextcloud/client/etm/EtmActivity.kt b/app/src/main/java/com/nextcloud/client/etm/EtmActivity.kt index 9d5b72a43f7c..61fbe2736e2a 100644 --- a/app/src/main/java/com/nextcloud/client/etm/EtmActivity.kt +++ b/app/src/main/java/com/nextcloud/client/etm/EtmActivity.kt @@ -10,6 +10,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.view.MenuItem +import androidx.activity.OnBackPressedCallback import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import com.nextcloud.client.di.Injectable @@ -46,6 +47,7 @@ class EtmActivity : onPageChanged(it) } ) + handleOnBackPressed() } override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { @@ -58,11 +60,17 @@ class EtmActivity : else -> super.onOptionsItemSelected(item) } - @Deprecated("Deprecated in Java") - override fun onBackPressed() { - if (!vm.onBackPressed()) { - super.onBackPressed() - } + private fun handleOnBackPressed() { + onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + val handledByVm = vm.onBackPressed() + + if (!handledByVm) { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + } + } + }) } private fun onPageChanged(page: EtmMenuEntry?) { diff --git a/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.kt b/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.kt index a824c7ca41b1..dd51319fc54f 100644 --- a/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.kt +++ b/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.kt @@ -132,6 +132,7 @@ class WhatsNewActivity : object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { onFinish() + isEnabled = false onBackPressedDispatcher.onBackPressed() } } diff --git a/app/src/main/java/com/nextcloud/utils/extensions/DrawerActivityExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/DrawerActivityExtensions.kt index d09660301611..899d9ed5a241 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/DrawerActivityExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/DrawerActivityExtensions.kt @@ -1,7 +1,7 @@ /* * Nextcloud - Android Client * - * SPDX-FileCopyrightText: 2024 Alper Ozturk + * SPDX-FileCopyrightText: 2025 Alper Ozturk * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -10,22 +10,10 @@ package com.nextcloud.utils.extensions import android.content.Intent import com.owncloud.android.MainApp import com.owncloud.android.R -import com.owncloud.android.datamodel.OCFile import com.owncloud.android.ui.activity.DrawerActivity import com.owncloud.android.ui.activity.FileDisplayActivity -@Suppress("ReturnCount") -fun DrawerActivity.handleBackButtonEvent(currentDir: OCFile): Boolean { - if (DrawerActivity.menuItemId == R.id.nav_all_files && currentDir.isRootDirectory) { - moveTaskToBack(true) - return true - } - - val isParentDirExists = (storageManager.getFileById(currentDir.parentId) != null) - if (isParentDirExists) { - return false - } - +fun DrawerActivity.navigateToAllFiles() { DrawerActivity.menuItemId = R.id.nav_all_files setNavigationViewItemChecked() @@ -38,6 +26,4 @@ fun DrawerActivity.handleBackButtonEvent(currentDir: OCFile): Boolean { }.run { startActivity(this) } - - return true } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index 29aa804614f2..2b0d1c0d2c2e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -31,6 +31,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.os.PersistableBundle; import android.os.SystemClock; import android.text.TextUtils; import android.view.Menu; @@ -115,6 +116,7 @@ import javax.inject.Inject; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -206,6 +208,12 @@ public abstract class DrawerActivity extends ToolbarActivity @Inject ClientFactory clientFactory; + @Override + public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { + super.onCreate(savedInstanceState, persistentState); + addOnBackPressedCallback(); + } + /** * Initializes the drawer and its content. This method needs to be called after the content view has been set. */ @@ -1153,19 +1161,24 @@ public void onConfigurationChanged(@NonNull Configuration newConfig) { } } - @Override - public void onBackPressed() { - if (isDrawerOpen()) { - closeDrawer(); - return; - } - Fragment fileDetailsSharingProcessFragment = - getSupportFragmentManager().findFragmentByTag(FileDetailsSharingProcessFragment.TAG); - if (fileDetailsSharingProcessFragment != null) { - ((FileDetailsSharingProcessFragment) fileDetailsSharingProcessFragment).onBackPressed(); - } else { - super.onBackPressed(); - } + public void addOnBackPressedCallback() { + getOnBackPressedDispatcher().addCallback(new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + if (isDrawerOpen()) { + closeDrawer(); + return; + } + + final var fragment = getSupportFragmentManager().findFragmentByTag(FileDetailsSharingProcessFragment.TAG); + if (fragment instanceof FileDetailsSharingProcessFragment fileDetailsSharingProcessFragment) { + fileDetailsSharingProcessFragment.onBackPressed(); + } else { + setEnabled(false); + getOnBackPressedDispatcher().onBackPressed(); + } + } + }); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 301c4e6d67a2..88807ba9fc82 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -40,6 +40,7 @@ import android.view.MenuItem import android.view.View import android.view.ViewTreeObserver.OnGlobalLayoutListener import android.view.WindowManager.BadTokenException +import androidx.activity.OnBackPressedCallback import androidx.annotation.VisibleForTesting import androidx.appcompat.widget.SearchView import androidx.core.view.MenuItemCompat @@ -82,6 +83,7 @@ import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.isActive import com.nextcloud.utils.extensions.lastFragment import com.nextcloud.utils.extensions.logFileSize +import com.nextcloud.utils.extensions.navigateToAllFiles import com.nextcloud.utils.fileNameValidator.FileNameValidator.checkFolderPath import com.nextcloud.utils.view.FastScrollUtils import com.owncloud.android.MainApp @@ -155,7 +157,6 @@ import com.owncloud.android.utils.PermissionUtil.requestNotificationPermission import com.owncloud.android.utils.PushUtils import com.owncloud.android.utils.StringUtils import com.owncloud.android.utils.theme.CapabilityUtils -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -278,6 +279,7 @@ class FileDisplayActivity : initSyncBroadcastReceiver() observeWorkerState() startMetadataSyncForRoot() + handleBackPress() } private fun loadSavedInstanceState(savedInstanceState: Bundle?) { @@ -935,7 +937,7 @@ class FileDisplayActivity : ) { openDrawer() } else { - onBackPressed() + onBackPressedDispatcher.onBackPressed() } } else if (itemId == R.id.action_select_all) { val fragment = this.listOfFilesFragment @@ -1136,40 +1138,59 @@ class FileDisplayActivity : } } - private val isRootDirectory: Boolean - get() { - val currentDir = getCurrentDir() - return (currentDir == null || currentDir.parentId == FileDataStorageManager.ROOT_PARENT_ID.toLong()) - } - - /* - * BackPressed priority/hierarchy: - * 1. close search view if opened - * 2. close drawer if opened - * 3. if it is OCFileListFragment and it's in Root -> (finish Activity) or it's not Root -> (browse up) - * 4. otherwise pop up the fragment and sortGroup view visibility and call super.onBackPressed() + /** + * Sets up a custom back-press handler for this activity. + * + * This callback determines how the back button behaves based on the current UI state: + * - If the search view is open, it closes it. + * - If the navigation drawer is open, it closes it. + * - If the left fragment is an [OCFileListFragment]: + * - If in the root directory, it either navigates to "All Files" or finishes the activity. + * - Otherwise, it navigates one level up. + * - Otherwise, it pops the current fragment from the back stack. + * + * ### About `isEnabled` + * `isEnabled` is a property of [OnBackPressedCallback]. + * When `isEnabled = false`, this callback is **temporarily disabled**, + * allowing the system or other callbacks to handle the back press instead. */ - @SuppressFBWarnings("ITC_INHERITANCE_TYPE_CHECKING") // TODO Apply fail fast principle - override fun onBackPressed() { - if (isSearchOpen()) { - resetSearchAction() - return - } + private fun handleBackPress() { + onBackPressedDispatcher.addCallback( + this, + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + when { + isSearchOpen() -> { + isEnabled = false + resetSearchAction() + } - if (isDrawerOpen) { - super.onBackPressed() - return - } + isDrawerOpen -> { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + } - if (this.leftFragment is OCFileListFragment) { - if (isRoot(getCurrentDir())) { - finish() - } else { - browseUp(leftFragment as OCFileListFragment) + leftFragment is OCFileListFragment -> { + val fragment = leftFragment as OCFileListFragment + if (isRoot(getCurrentDir())) { + if (fragment.shouldNavigateBackToAllFiles()) { + navigateToAllFiles() + } else { + finish() + } + } else { + browseUp(fragment) + } + } + + else -> { + isEnabled = false + popBack() + } + } + } } - } else { - popBack() - } + ) } private fun browseUp(listOfFiles: OCFileListFragment) { @@ -1210,20 +1231,20 @@ class FileDisplayActivity : if (leftFragment is UnifiedSearchFragment) { showSortListGroup(false) - super.onBackPressed() + onBackPressedDispatcher.onBackPressed() } } /** * Use this method when want to pop the fragment on back press. It resets Scrolling (See * [with true][.resetScrolling] and pop the visibility for sortListGroup (See - * [with false][.showSortListGroup]. At last call to super.onBackPressed() + * [with false][.showSortListGroup]. At last call to onBackPressedDispatcher.onBackPressed() */ private fun popBack() { binding.fabMain.setImageResource(R.drawable.ic_plus) resetScrolling(true) showSortListGroup(false) - super.onBackPressed() + onBackPressedDispatcher.onBackPressed() } override fun onSaveInstanceState(outState: Bundle) { @@ -1645,7 +1666,7 @@ class FileDisplayActivity : if (uploadWasFine || file != null && file.fileExists()) { fileDetailFragment.updateFileDetails(false, true) } else { - onBackPressed() + onBackPressedDispatcher.onBackPressed() } // Force the preview if the file is an image or text file diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt index 85ead7b2c9b8..a9a2a2adfb13 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt @@ -106,7 +106,7 @@ open class FolderPickerActivity : updateActionBarTitleAndHomeButtonByString(captionText) setBackgroundText() - handleOnBackPressed() + handleBackPress() } override fun onDestroy() { @@ -151,7 +151,7 @@ open class FolderPickerActivity : } } - private fun handleOnBackPressed() { + private fun handleBackPress() { onBackPressedDispatcher.addCallback( this, object : OnBackPressedCallback(true) { @@ -327,7 +327,7 @@ open class FolderPickerActivity : } else if (itemId == android.R.id.home) { val currentDir = currentFolder if (currentDir != null && currentDir.parentId != 0L) { - onBackPressed() + onBackPressedDispatcher.onBackPressed() } } else { retval = super.onOptionsItemSelected(item) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/InternalTwoWaySyncActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/InternalTwoWaySyncActivity.kt index 8ae77e6986bf..89d37b84da4d 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/InternalTwoWaySyncActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/InternalTwoWaySyncActivity.kt @@ -201,7 +201,7 @@ class InternalTwoWaySyncActivity : override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { android.R.id.home -> { - onBackPressed() + onBackPressedDispatcher.onBackPressed() } R.id.action_dismiss_two_way_sync -> { disableTwoWaySyncAndWorkers() diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.kt index 65c4d0715bb1..ef3526ecdcfd 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.kt @@ -91,7 +91,7 @@ class ManageAccountsActivity : multipleAccountsSupported = multiAccountSupport(this) setupUserList() - handleOnBackPressed() + handleBackPress() } private fun setupUsers() { @@ -149,7 +149,7 @@ class ManageAccountsActivity : performAccountRemoval(user) } - private fun handleOnBackPressed() { + private fun handleBackPress() { onBackPressedDispatcher.addCallback( this, onBackPressedCallback @@ -160,13 +160,13 @@ class ManageAccountsActivity : override fun handleOnBackPressed() { val resultIntent = Intent() - if (accountManager.allUsers.size > 0) { + if (accountManager.allUsers.isNotEmpty()) { resultIntent.putExtra(KEY_ACCOUNT_LIST_CHANGED, hasAccountListChanged()) resultIntent.putExtra(KEY_CURRENT_ACCOUNT_CHANGED, hasCurrentAccountChanged()) setResult(RESULT_OK, resultIntent) } else { val intent = Intent(this@ManageAccountsActivity, AuthenticatorActivity::class.java) - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP startActivity(intent) } @@ -229,7 +229,7 @@ class ManageAccountsActivity : var result = true if (item.itemId == android.R.id.home) { - onBackPressed() + onBackPressedDispatcher.onBackPressed() } else { result = super.onOptionsItemSelected(item) } @@ -331,7 +331,7 @@ class ManageAccountsActivity : ) recyclerView?.adapter = userListAdapter } else { - onBackPressed() + onBackPressedDispatcher.onBackPressed() } } @@ -393,8 +393,7 @@ class ManageAccountsActivity : resultIntent.putExtra(KEY_ACCOUNT_LIST_CHANGED, true) resultIntent.putExtra(KEY_CURRENT_ACCOUNT_CHANGED, true) setResult(RESULT_OK, resultIntent) - - super.onBackPressed() + onBackPressedDispatcher.onBackPressed() } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java index c9b4be929b4d..5148c10f52ec 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java @@ -103,6 +103,7 @@ import javax.inject.Inject; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -203,6 +204,8 @@ protected void onCreate(Bundle savedInstanceState) { fm.beginTransaction() .add(taskRetainerFragment, TaskRetainerFragment.FTAG_TASK_RETAINER_FRAGMENT).commit(); } // else, Fragment already created and retained across configuration change + + handleBackPress(); } @Override @@ -656,14 +659,19 @@ private File createTempFile(String text) { } } - @Override - public void onBackPressed() { - if (mParents.size() <= SINGLE_PARENT) { - super.onBackPressed(); - } else { - mParents.pop(); - browseToFolderIfItExists(); - } + private void handleBackPress() { + getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + if (mParents.size() <= SINGLE_PARENT) { + setEnabled(false); + getOnBackPressedDispatcher().onBackPressed(); + } else { + mParents.pop(); + browseToFolderIfItExists(); + } + } + }); } @Override @@ -1097,7 +1105,7 @@ public boolean onOptionsItemSelected(MenuItem item) { dialog.show(getSupportFragmentManager(), CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT); } else if (itemId == android.R.id.home) { if (mParents.size() > SINGLE_PARENT) { - onBackPressed(); + getOnBackPressedDispatcher().onBackPressed(); } } else if (itemId == R.id.action_switch_account) { showAccountChooserDialog(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java index bcbed6b84d77..0790160d7edb 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java @@ -15,6 +15,7 @@ */ package com.owncloud.android.ui.activity; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; @@ -354,6 +355,7 @@ private void setupAboutCategory(String appVersion) { } } + @SuppressLint("GestureBackNavigation") @Override public void onBackPressed() { DrawerActivity.menuItemId = R.id.nav_all_files; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java index 226bb6d294b2..375458b4bbe4 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java @@ -238,7 +238,7 @@ public void onCreate(Bundle savedInstanceState) { public void onItemSelected(AdapterView parent, View view, int position, long id) { int i = position; while (i-- != 0) { - onBackPressed(); + getOnBackPressedDispatcher().onBackPressed(); } // the next operation triggers a new call to this method, but it's necessary to // ensure that the name exposed in the action bar is the current directory when the @@ -311,7 +311,7 @@ public boolean onOptionsItemSelected(MenuItem item) { if (itemId == android.R.id.home) { if (mCurrentDir != null && mCurrentDir.getParentFile() != null) { - onBackPressed(); + getOnBackPressedDispatcher().onBackPressed(); } } else if (itemId == R.id.action_select_all) { mSelectAll = !item.isChecked(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java index 613437a25133..44bdca6655b7 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java @@ -158,7 +158,7 @@ public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); if (itemId == android.R.id.home) { - onBackPressed(); + getOnBackPressedDispatcher().onBackPressed(); } else if (itemId == R.id.action_open_account) { accountClicked(user.hashCode()); } else if (itemId == R.id.action_delete_account) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt index a88da8904661..6224420f5256 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt @@ -25,7 +25,6 @@ import android.os.Handler import android.os.Looper import android.os.Parcelable import android.util.DisplayMetrics -import android.view.KeyEvent import android.view.LayoutInflater import android.view.Menu import android.view.MenuInflater @@ -57,7 +56,6 @@ import com.nextcloud.client.di.Injectable import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.client.preferences.AppPreferencesImpl import com.nextcloud.utils.extensions.getTypedActivity -import com.nextcloud.utils.extensions.handleBackButtonEvent import com.owncloud.android.MainApp import com.owncloud.android.R import com.owncloud.android.databinding.ListFragmentBinding @@ -65,7 +63,6 @@ import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.SearchRemoteOperation import com.owncloud.android.lib.resources.status.OwnCloudVersion import com.owncloud.android.ui.EmptyRecyclerView -import com.owncloud.android.ui.activity.FileActivity import com.owncloud.android.ui.activity.FileDisplayActivity import com.owncloud.android.ui.activity.FolderPickerActivity import com.owncloud.android.ui.activity.OnEnforceableRefreshListener @@ -767,19 +764,6 @@ open class ExtendedListFragment : } } - protected fun setupBackButtonRedirectToAllFiles() { - view?.isFocusableInTouchMode = true - view?.requestFocus() - view?.setOnKeyListener { _: View, keyCode: Int, event: KeyEvent -> - if (event.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) { - val fda = getTypedActivity(FileActivity::class.java) - val currentDir = fda?.currentDir ?: return@setOnKeyListener false - return@setOnKeyListener fda.handleBackButtonEvent(currentDir) - } - false - } - } - private data class EmptyListData(val headline: Int, val message: Int, val icon: Int?, val tintIcon: Boolean) companion object { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 858c02ec128a..f94e553eb7d0 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -197,7 +197,7 @@ public FileDetailActivitiesFragment getFileDetailActivitiesFragment() { } public void goBackToOCFileListFragment() { - requireActivity().onBackPressed(); + requireActivity().getOnBackPressedDispatcher().onBackPressed(); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java index 672ca0f2ae64..c44c12168a2a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java @@ -234,12 +234,6 @@ public void onResume() { } } - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setupBackButtonRedirectToAllFiles(); - } - @Override public void onMessageEvent(ChangeMenuEvent changeMenuEvent) { super.onMessageEvent(changeMenuEvent); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 8961b2fdbbcf..8623c5420cb4 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -277,12 +277,6 @@ public void onResume() { super.onResume(); } - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setupBackButtonRedirectToAllFiles(); - } - @Override public void onDestroyView() { super.onDestroyView(); @@ -2325,4 +2319,15 @@ public boolean isEmpty() { public SearchEvent getSearchEvent() { return searchEvent; } + + public boolean isSearchEventFavorite() { + if (searchEvent == null) { + return false; + } + return searchEvent.getSearchType() == SearchRemoteOperation.SearchType.FAVORITE_SEARCH; + } + + public boolean shouldNavigateBackToAllFiles() { + return ((this instanceof GalleryFragment) || isSearchEventFavorite() || DrawerActivity.menuItemId == R.id.nav_favorites); + } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListFragment.java index 03c8f0e52786..99ff53f53368 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListFragment.java @@ -404,7 +404,7 @@ private void importCalendar() { private void closeFragment() { ContactsPreferenceActivity contactsPreferenceActivity = (ContactsPreferenceActivity) getActivity(); if (contactsPreferenceActivity != null) { - contactsPreferenceActivity.onBackPressed(); + contactsPreferenceActivity.getOnBackPressedDispatcher().onBackPressed(); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewBitmapActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewBitmapActivity.kt index c5265015bb21..b6c9e86c2d16 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewBitmapActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewBitmapActivity.kt @@ -54,7 +54,7 @@ class PreviewBitmapActivity : } override fun onSupportNavigateUp(): Boolean { - onBackPressed() + onBackPressedDispatcher.onBackPressed() return true } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt index c71c86bd2930..1d575dd32f5a 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt @@ -14,6 +14,7 @@ import android.os.Build import android.os.Bundle import android.view.MenuItem import android.view.View +import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.ActionBar import androidx.core.content.ContextCompat import androidx.drawerlayout.widget.DrawerLayout @@ -123,6 +124,7 @@ class PreviewImageActivity : observeWorkerState() applyDisplayCutOutTopPadding() + handleBackPress() } private fun applyDisplayCutOutTopPadding() { @@ -214,9 +216,14 @@ class PreviewImageActivity : } } - override fun onBackPressed() { - sendRefreshSearchEventBroadcast() - super.onBackPressed() + private fun handleBackPress() { + onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + sendRefreshSearchEventBroadcast() + isEnabled = false + onBackPressedDispatcher.onBackPressed() + } + }) } override fun onOptionsItemSelected(item: MenuItem): Boolean { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.kt index a3aec178ad48..99b0bffc4bf3 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.kt @@ -165,7 +165,7 @@ abstract class PreviewTextFragment : * Finishes the preview */ protected fun finish() { - requireActivity().runOnUiThread { requireActivity().onBackPressed() } + requireActivity().runOnUiThread { requireActivity().onBackPressedDispatcher.onBackPressed() } } companion object { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewVideoFullscreenDialog.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewVideoFullscreenDialog.kt index 30b9da6a53cb..dd1e6814eccc 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewVideoFullscreenDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewVideoFullscreenDialog.kt @@ -7,15 +7,16 @@ */ package com.owncloud.android.ui.preview -import android.app.Activity import android.app.Dialog import android.os.Build import android.view.ViewGroup import android.view.Window +import androidx.activity.addCallback import androidx.annotation.OptIn import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat +import androidx.fragment.app.FragmentActivity import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.ExoPlayer import androidx.media3.ui.PlayerView @@ -35,7 +36,7 @@ import com.owncloud.android.lib.common.utils.Log_OC */ @OptIn(UnstableApi::class) class PreviewVideoFullscreenDialog( - private val activity: Activity, + private val activity: FragmentActivity, nextcloudClient: NextcloudClient, private val sourceExoPlayer: ExoPlayer, private val sourceView: PlayerView @@ -69,6 +70,7 @@ class PreviewVideoFullscreenDialog( binding.videoPlayer.player = mExoPlayer mExoPlayer.prepare() } + handleOnBackPressed() } private fun isRotatedVideo(): Boolean { @@ -95,7 +97,7 @@ class PreviewVideoFullscreenDialog( setOnShowListener { enableImmersiveMode() switchTargetViewFromSource() - binding.videoPlayer.setFullscreenButtonClickListener { onBackPressed() } + binding.videoPlayer.setFullscreenButtonClickListener { activity.onBackPressedDispatcher.onBackPressed() } if (isPlaying) { mExoPlayer.play() } @@ -111,23 +113,25 @@ class PreviewVideoFullscreenDialog( } } - override fun onBackPressed() { - val isPlaying = mExoPlayer.isPlaying - if (isPlaying) { - mExoPlayer.pause() - } - setOnDismissListener { - disableImmersiveMode() - playingStateListener?.let { - mExoPlayer.removeListener(it) - } - switchTargetViewToSource() + private fun handleOnBackPressed() { + activity.onBackPressedDispatcher.addCallback(activity) { + val isPlaying = mExoPlayer.isPlaying if (isPlaying) { - sourceExoPlayer.play() + mExoPlayer.pause() + } + setOnDismissListener { + disableImmersiveMode() + playingStateListener?.let { + mExoPlayer.removeListener(it) + } + switchTargetViewToSource() + if (isPlaying) { + sourceExoPlayer.play() + } + sourceView.showController() } - sourceView.showController() + dismiss() } - dismiss() } private fun switchTargetViewToSource() { diff --git a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt index 9fb6a8fd8eb0..2ceef02b13e3 100644 --- a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt @@ -128,6 +128,7 @@ class TrashbinActivity : updateActionBarTitleAndHomeButtonByString(getString(R.string.trashbin_activity_title)) setupDrawer() + handleBackPress() } override fun onStart() { @@ -179,8 +180,6 @@ class TrashbinActivity : loadFolder() - handleOnBackPressed() - mMultiChoiceModeListener = MultiChoiceModeListener( this, trashbinListAdapter, @@ -189,7 +188,7 @@ class TrashbinActivity : addDrawerListener(mMultiChoiceModeListener) } - private fun handleOnBackPressed() { + private fun handleBackPress() { onBackPressedDispatcher.addCallback( this, onBackPressedCallback diff --git a/appscan/build.gradle b/appscan/build.gradle index 2dd65e4eabb9..00984b58de8d 100644 --- a/appscan/build.gradle +++ b/appscan/build.gradle @@ -22,8 +22,8 @@ android { defaultConfig { minSdk = 27 - targetSdk = 35 - compileSdk = 35 + targetSdk = 36 + compileSdk = 36 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/build.gradle b/build.gradle index 14482f6f01d7..e482d00f8d3b 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ */ buildscript { ext { - androidLibraryVersion ="5da34c70da4068ff976cf931b7716fc7a337f32d" + androidLibraryVersion ="9b7c9434bf9002a63d5ac911b89b4abf014fabfd" androidCommonLibraryVersion = "0.28.0" androidPluginVersion = '8.13.0' androidxMediaVersion = "1.5.1" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 48465f5b1b02..88bf5cf9ec06 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -16382,6 +16382,14 @@ + + + + + + + +