Skip to content

Commit 8fe226e

Browse files
committed
Guards and null checks against unsaved fragment transactions on configuration change
Fixes #1555
1 parent da62dc2 commit 8fe226e

File tree

5 files changed

+398
-123
lines changed

5 files changed

+398
-123
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package com.amaze.filemanager.ui.fragments
2+
3+
import android.content.pm.ActivityInfo
4+
import androidx.test.espresso.Espresso.onView
5+
import androidx.test.espresso.action.ViewActions.swipeLeft
6+
import androidx.test.espresso.action.ViewActions.swipeRight
7+
import androidx.test.espresso.matcher.ViewMatchers.withId
8+
import androidx.test.ext.junit.runners.AndroidJUnit4
9+
import androidx.test.platform.app.InstrumentationRegistry
10+
import androidx.test.rule.ActivityTestRule
11+
import androidx.test.rule.GrantPermissionRule
12+
import com.amaze.filemanager.R
13+
import com.amaze.filemanager.ui.activities.MainActivity
14+
import org.junit.Rule
15+
import org.junit.Test
16+
import org.junit.runner.RunWith
17+
18+
/**
19+
* Tests for [TabFragment] functionality, mainly for
20+
* https://github.com/TeamAmaze/AmazeFileManager/issues/1555.
21+
*
22+
* Note: deprecated methods and classes are used here for best reproducing the issues.
23+
*/
24+
@Suppress("DEPRECATION")
25+
@RunWith(AndroidJUnit4::class)
26+
class TabFragmentTest {
27+
@get:Rule
28+
val activityRule = ActivityTestRule(MainActivity::class.java)
29+
30+
@Rule
31+
@JvmField
32+
val storagePermissionRule: GrantPermissionRule =
33+
GrantPermissionRule
34+
.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
35+
36+
/**
37+
* Check if the fragment state is saved correctly during a configuration change
38+
* by rotate the screen while swiping between the tabs.
39+
*/
40+
@Test
41+
fun testFragmentStateSavingDuringConfigChange() {
42+
// First perform the swipe action
43+
onView(withId(R.id.pager)).perform(swipeLeft())
44+
45+
// Force a configuration change by rotating the screen
46+
activityRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
47+
Thread.sleep(1000) // Give time for the rotation to complete
48+
activityRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
49+
}
50+
51+
/**
52+
* Check if the fragment state is saved correctly during rapid tab swiping.
53+
*/
54+
@Test
55+
fun testRapidTabSwitchingAndStateSaving() {
56+
// Perform rapid tab switches
57+
repeat(10) {
58+
onView(withId(R.id.pager)).perform(swipeLeft())
59+
Thread.sleep(100) // Small delay to ensure swipe completes
60+
onView(withId(R.id.pager)).perform(swipeRight())
61+
Thread.sleep(100) // Small delay to ensure swipe completes
62+
}
63+
64+
// Force a save state by rotating
65+
activityRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
66+
}
67+
68+
/**
69+
* Check if the fragment state is saved correctly when the fragment is detached.
70+
*/
71+
@Test
72+
fun testFragmentDetachmentAndStateSaving() {
73+
// First switch to a different tab
74+
onView(withId(R.id.pager)).perform(swipeLeft())
75+
76+
// Get the TabFragment
77+
InstrumentationRegistry.getInstrumentation().runOnMainSync {
78+
val activity = activityRule.activity
79+
val tabFragment =
80+
activity.supportFragmentManager
81+
.findFragmentById(R.id.content_frame) as TabFragment
82+
83+
// Detach fragment through FragmentManager
84+
activity.supportFragmentManager.beginTransaction().apply {
85+
tabFragment.fragments.firstOrNull()?.let { detach(it) }
86+
commit()
87+
}
88+
}
89+
90+
// Force state save through configuration change
91+
activityRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
92+
}
93+
}

app/src/main/java/com/amaze/filemanager/adapters/RecyclerAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ public void createHeaders(boolean invalidate, List<IconDataParcelable> uris) {
683683

684684
@Override
685685
public int getItemCount() {
686-
return getItemsDigested().size();
686+
return getItemsDigested() != null ? getItemsDigested().size() : 0;
687687
}
688688

689689
@Override

0 commit comments

Comments
 (0)