Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package com.amaze.filemanager.ui.fragments

import android.content.Context
import android.content.pm.ActivityInfo
import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES.TIRAMISU
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.swipeLeft
import androidx.test.espresso.action.ViewActions.swipeRight
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
import androidx.test.rule.GrantPermissionRule
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
import com.amaze.filemanager.R
import com.amaze.filemanager.ui.activities.MainActivity
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith


/**
* Tests for [TabFragment] functionality, mainly for
* https://github.com/TeamAmaze/AmazeFileManager/issues/1555.
*
* Note: deprecated methods and classes are used here for best reproducing the issues.
*/
@Suppress("DEPRECATION")
@RunWith(AndroidJUnit4::class)
class TabFragmentTest {
@get:Rule
val activityRule = ActivityTestRule(MainActivity::class.java)

@Rule
@JvmField
val storagePermissionRule: GrantPermissionRule =
GrantPermissionRule
.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)

@Rule
@JvmField
val notificationPermissionRule: GrantPermissionRule = if(SDK_INT >= TIRAMISU) {
GrantPermissionRule.grant(android.Manifest.permission.POST_NOTIFICATIONS)
} else {
GrantPermissionRule.grant()
}

/**
* From https://github.com/android/android-test/issues/1658#issue-1551755250
* HACK this grants access to external storage "manually" because other solutions don't seem
* to set the permission.
*/
@Before
fun grantManageStoragePermission() {
val context: Context = InstrumentationRegistry.getInstrumentation().targetContext
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

val amazeResources = context.packageManager.getResourcesForApplication(context.packageName)
val grantPermissionExplanation = amazeResources.getString(R.string.grant_all_files_permission)

if (device.hasObject(By.text(grantPermissionExplanation))) {
// First press Amaze's grant button
onView(withText(R.string.grant)).perform(click())

// Identifier names are taken here:
// https://cs.android.com/android/platform/superproject/+/master:packages/apps/Settings/res/values/strings.xml
val resources = context.packageManager.getResourcesForApplication("com.android.settings")
val resId = resources.getIdentifier(
"permit_manage_external_storage",
"string",
"com.android.settings"
)
val permitManageExternalStorage = resources.getString(resId)

val grantToggle =
device.findObject(UiSelector().textMatches("(?i)$permitManageExternalStorage"))
grantToggle.click()
device.pressBack()
}
}

/**
* This test causes a rotation to happen while the MainFragment detaches, to check if it
* fails. This could happen in reality, but should be very rare
*/
@Test
fun testFragmentStateSavingDuringDetachment() {
activityRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE

// Get the TabFragment
InstrumentationRegistry.getInstrumentation().runOnMainSync {
val activity = activityRule.activity
val tabFragment =
activity.supportFragmentManager
.findFragmentById(R.id.content_frame) as TabFragment

// Detach fragment through FragmentManager
activity.supportFragmentManager.beginTransaction().apply {
tabFragment.fragments.forEach { detach(it) }
commit()
}
}
}

/**
* Check if the fragment state is saved correctly during a configuration change
* by rotate the screen while swiping between the tabs.
*/
@Test
fun testFragmentStateSavingDuringConfigChange() {
// First perform the swipe action
onView(withId(R.id.pager)).perform(swipeLeft())

// Force a configuration change by rotating the screen
activityRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
Thread.sleep(1000) // Give time for the rotation to complete
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is using a constant time correct here? Doesn't it depend on the speed of the device whether it crashes or not?

activityRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}

/**
* Check if the fragment state is saved correctly during rapid tab swiping.
*/
@Test
fun testRapidTabSwitchingAndStateSaving() {
// Perform rapid tab switches
repeat(10) {
onView(withId(R.id.pager)).perform(swipeLeft())
Thread.sleep(100) // Small delay to ensure swipe completes
onView(withId(R.id.pager)).perform(swipeRight())
Thread.sleep(100) // Small delay to ensure swipe completes
}

// Force a save state by rotating
activityRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
}

/**
* Check if the fragment state is saved correctly when the fragment is detached.
*/
@Test
fun testFragmentDetachmentAndStateSaving() {
// First switch to a different tab
onView(withId(R.id.pager)).perform(swipeLeft())

// Get the TabFragment
InstrumentationRegistry.getInstrumentation().runOnMainSync {
val activity = activityRule.activity
val tabFragment =
activity.supportFragmentManager
.findFragmentById(R.id.content_frame) as TabFragment

// Detach fragment through FragmentManager
activity.supportFragmentManager.beginTransaction().apply {
tabFragment.fragments.firstOrNull()?.let { detach(it) }
commit()
}
}

// Force state save through configuration change
activityRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ public void createHeaders(boolean invalidate, List<IconDataParcelable> uris) {

@Override
public int getItemCount() {
return getItemsDigested().size();
return getItemsDigested() != null ? getItemsDigested().size() : 0;
}

@Override
Expand Down
Loading
Loading