Prevent crash caused by dialog show when state saved.

Call dialog.show when state saved will cause IllegalStateException so we
should prevent this.

Fix: 139883603
Test: manual
Test: atest DocumentsUIGoogleTests
Change-Id: I7ada873a7573729744d039347f688d127c972d41
diff --git a/src/com/android/documentsui/CreateDirectoryFragment.java b/src/com/android/documentsui/CreateDirectoryFragment.java
index 0d4aa4f..1a35cbd 100644
--- a/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -61,6 +61,11 @@
     private static final String TAG_CREATE_DIRECTORY = "create_directory";
 
     public static void show(FragmentManager fm) {
+        if (fm.isStateSaved()) {
+            Log.w(TAG, "Skip show create folder dialog because state saved");
+            return;
+        }
+
         final CreateDirectoryFragment dialog = new CreateDirectoryFragment();
         dialog.show(fm, TAG_CREATE_DIRECTORY);
     }
diff --git a/src/com/android/documentsui/dirlist/RenameDocumentFragment.java b/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
index 0a25395..9bcfd56 100644
--- a/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
+++ b/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
@@ -60,6 +60,11 @@
     private @Nullable DialogInterface mDialog;
 
     public static void show(FragmentManager fm, DocumentInfo document) {
+        if (fm.isStateSaved()) {
+            Log.w(TAG, "Skip show rename dialog because state saved");
+            return;
+        }
+
         final RenameDocumentFragment dialog = new RenameDocumentFragment();
         dialog.mDocument = document;
         dialog.show(fm, TAG_RENAME_DOCUMENT);
diff --git a/src/com/android/documentsui/files/DeleteDocumentFragment.java b/src/com/android/documentsui/files/DeleteDocumentFragment.java
index 12f7b3c..64393a3 100644
--- a/src/com/android/documentsui/files/DeleteDocumentFragment.java
+++ b/src/com/android/documentsui/files/DeleteDocumentFragment.java
@@ -15,9 +15,12 @@
  */
 package com.android.documentsui.files;
 
+import static com.android.documentsui.base.SharedMinimal.TAG;
+
 import android.app.Dialog;
 import android.content.Context;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.widget.Button;
 import android.widget.TextView;
@@ -54,6 +57,11 @@
      * @param srcParent the parent document of the selection
      */
     public static void show(FragmentManager fm, List<DocumentInfo> docs, DocumentInfo srcParent) {
+        if (fm.isStateSaved()) {
+            Log.w(TAG, "Skip show delete dialog because state saved");
+            return;
+        }
+
         final DeleteDocumentFragment dialog = new DeleteDocumentFragment();
         dialog.mDocuments = docs;
         dialog.mSrcParent = srcParent;
diff --git a/src/com/android/documentsui/queries/SearchFragment.java b/src/com/android/documentsui/queries/SearchFragment.java
index 5eb7435..b98efe0 100644
--- a/src/com/android/documentsui/queries/SearchFragment.java
+++ b/src/com/android/documentsui/queries/SearchFragment.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -59,6 +60,11 @@
     private List<String> mHistoryList;
 
     public static void showFragment(FragmentManager fm, String initQuery) {
+        if (fm.isStateSaved()) {
+            Log.w(TAG, "Skip show because state saved");
+            return;
+        }
+
         final SearchFragment fragment = new SearchFragment();
         final Bundle args = new Bundle();
         args.putString(KEY_QUERY, initQuery);
diff --git a/src/com/android/documentsui/sorting/SortListFragment.java b/src/com/android/documentsui/sorting/SortListFragment.java
index 7030f74..7c33c9d 100644
--- a/src/com/android/documentsui/sorting/SortListFragment.java
+++ b/src/com/android/documentsui/sorting/SortListFragment.java
@@ -1,8 +1,11 @@
 package com.android.documentsui.sorting;
 
+import static com.android.documentsui.base.SharedMinimal.TAG;
+
 import android.app.Dialog;
 import android.content.Context;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
@@ -34,6 +37,11 @@
     private List<SortItem> mSortingList;
 
     public static void show(FragmentManager fm, SortModel model) {
+        if (fm.isStateSaved()) {
+            Log.w(TAG, "Skip show sort dialog because state saved");
+            return;
+        }
+
         if (fm.findFragmentByTag(TAG_SORTING_LIST) == null) {
             SortListFragment fragment = new SortListFragment();
             Bundle args = new Bundle();
diff --git a/tests/common/com/android/documentsui/DialogFragmentTest.java b/tests/common/com/android/documentsui/DialogFragmentTest.java
index 05ad5fb..4e373a9 100644
--- a/tests/common/com/android/documentsui/DialogFragmentTest.java
+++ b/tests/common/com/android/documentsui/DialogFragmentTest.java
@@ -36,7 +36,13 @@
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.documentsui.base.DocumentInfo;
+import com.android.documentsui.dirlist.RenameDocumentFragment;
+import com.android.documentsui.files.DeleteDocumentFragment;
 import com.android.documentsui.files.FilesActivity;
+import com.android.documentsui.queries.SearchFragment;
+import com.android.documentsui.sorting.SortListFragment;
+import com.android.documentsui.sorting.SortModel;
 
 import com.google.android.material.textfield.TextInputEditText;
 
@@ -45,6 +51,7 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mockito;
 
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -202,6 +209,49 @@
         switchOrientation(mActivityTestRule.getActivity());
     }
 
+    @Test
+    public void testCreateDirectoryFragmentShows_skipWhenStateSaved() {
+        mFragmentManager = Mockito.mock(FragmentManager.class);
+        Mockito.when(mFragmentManager.isStateSaved()).thenReturn(true);
+
+        // Use mock FragmentManager will cause NPE then test fail when DialogFragment.show is
+        // called, so test pass means it skip.
+        CreateDirectoryFragment.show(mFragmentManager);
+    }
+
+    @Test
+    public void testDeleteDocumentFragmentShows_skipWhenStateSaved() {
+        mFragmentManager = Mockito.mock(FragmentManager.class);
+        Mockito.when(mFragmentManager.isStateSaved()).thenReturn(true);
+
+        DeleteDocumentFragment.show(mFragmentManager, null, null);
+    }
+
+    @Test
+    public void testRenameDocumentFragmentShows_skipWhenStateSaved() {
+        mFragmentManager = Mockito.mock(FragmentManager.class);
+        Mockito.when(mFragmentManager.isStateSaved()).thenReturn(true);
+
+        RenameDocumentFragment.show(mFragmentManager, new DocumentInfo());
+    }
+
+    @Test
+    public void testSearchFragmentShows_skipWhenStateSaved() {
+        mFragmentManager = Mockito.mock(FragmentManager.class);
+        Mockito.when(mFragmentManager.isStateSaved()).thenReturn(true);
+
+        SearchFragment.showFragment(mFragmentManager, "");
+    }
+
+    @Test
+    public void testSortListFragmentShows_skipWhenStateSaved() {
+        mFragmentManager = Mockito.mock(FragmentManager.class);
+        Mockito.when(mFragmentManager.isStateSaved()).thenReturn(true);
+        SortModel sortModel = Mockito.mock(SortModel.class);
+
+        SortListFragment.show(mFragmentManager, sortModel);
+    }
+
     private static int getInputTextHeight(TextInputEditText v) {
         Paint paint = v.getPaint();
         final float textSize = paint.getTextSize();