[Tab Model] Add DialogType to TabModelActionListener
Add a dialog type so that listeners know which type of dialog was
shown. Use this to determine behaviors as handling of the SYNC vs
COLLABORATION speedbump dialogs may differ.
Bug: 345854441
Change-Id: I13fab14b279059a334b8d786290b25c9a4a0ab9d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5983546
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Commit-Queue: Calder Kitagawa <ckitagawa@chromium.org>
Reviewed-by: Sky Malice <skym@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1377095}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabRemoverImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabRemoverImpl.java
index 57d76de..9d2de4db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabRemoverImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabRemoverImpl.java
@@ -15,6 +15,7 @@
import org.chromium.chrome.browser.data_sharing.DataSharingTabGroupUtils;
import org.chromium.chrome.browser.data_sharing.DataSharingTabGroupUtils.GroupsPendingDestroy;
import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabModelActionListener.DialogType;
import org.chromium.chrome.browser.tabmodel.TabModelRemover.TabModelRemoverFlowHandler;
import org.chromium.chrome.browser.tasks.tab_management.ActionConfirmationManager;
import org.chromium.components.browser_ui.widget.ActionConfirmationResult;
@@ -88,6 +89,7 @@
private final TabClosureParams mOriginalTabClosureParams;
private @Nullable TabModelActionListener mListener;
private @Nullable List<Tab> mPlaceholderTabs;
+ private boolean mPreventUndo;
CloseTabsHandler(
@NonNull TabGroupModelFilter tabGroupModelFilter,
@@ -113,7 +115,7 @@
@Override
public void showTabGroupDeletionConfirmationDialog(@NonNull Callback<Integer> onResult) {
- var adaptedCallback = adaptOnResultCallback(onResult, takeListener());
+ var adaptedCallback = adaptOnResultCallback(onResult, DialogType.SYNC, takeListener());
if (mOriginalTabClosureParams.isTabGroup) {
mActionConfirmationManager.processDeleteGroupAttempt(adaptedCallback);
} else {
@@ -124,12 +126,14 @@
@Override
public void showCollaborationKeepDialog(
@MemberRole int memberRole, @NonNull String title, Callback<Integer> onResult) {
+ var adaptedCallback =
+ adaptOnResultCallback(onResult, DialogType.COLLABORATION, takeListener());
if (memberRole == MemberRole.OWNER) {
mActionConfirmationManager.processCollaborationOwnerRemoveLastTab(
- title, adaptOnResultCallback(onResult, takeListener()));
+ title, adaptedCallback);
} else if (memberRole == MemberRole.MEMBER) {
mActionConfirmationManager.processCollaborationMemberRemoveLastTab(
- title, adaptOnResultCallback(onResult, takeListener()));
+ title, adaptedCallback);
} else {
assert false : "Not reached";
}
@@ -142,12 +146,14 @@
fixupTabClosureParams(
mTabGroupModelFilter.getTabModel(),
mOriginalTabClosureParams,
- mPlaceholderTabs);
+ mPlaceholderTabs,
+ mPreventUndo);
if (newTabClosureParams == null) return;
PassthroughTabRemover.doCloseTabs(mTabGroupModelFilter, newTabClosureParams);
if (mListener != null) {
- mListener.onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ mListener.onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
}
}
@@ -156,6 +162,26 @@
mListener = null;
return listener;
}
+
+ private @NonNull Callback<Integer> adaptOnResultCallback(
+ @NonNull Callback<Integer> callback,
+ @DialogType int plannedDialogType,
+ @Nullable TabModelActionListener listener) {
+ return (result) -> {
+ boolean isImmediateContinue = result == ActionConfirmationResult.IMMEDIATE_CONTINUE;
+ // Sync dialogs interrupt the flow and as such undo operations after the dialog is
+ // shown should be suppressed as the user already had an opportunity to abort.
+ if (plannedDialogType == DialogType.SYNC) {
+ mPreventUndo = !isImmediateContinue;
+ }
+ callback.onResult(result);
+ if (listener != null) {
+ @DialogType
+ int dialogType = isImmediateContinue ? DialogType.NONE : plannedDialogType;
+ listener.onConfirmationDialogResult(dialogType, result);
+ }
+ };
+ }
}
private static class RemoveTabHandler implements TabModelRemoverFlowHandler {
@@ -209,24 +235,25 @@
}
PassthroughTabRemover.doRemoveTab(tabModel, mTabToRemove);
if (mListener != null) {
- mListener.onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ mListener.onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
}
}
}
- // TODO(crbug.com/345854441): Consider overriding `allowUndo` in the event placeholder tabs were
- // not created and a dialog was shown to align with existing behaviors.
@VisibleForTesting
protected static @Nullable TabClosureParams fixupTabClosureParams(
@NonNull TabModel tabModel,
@NonNull TabClosureParams params,
- @Nullable List<Tab> placeholderTabs) {
+ @Nullable List<Tab> placeholderTabs,
+ boolean preventUndo) {
boolean createdPlaceholders = placeholderTabs != null && !placeholderTabs.isEmpty();
boolean isAllTabs = params.tabCloseType == TabCloseType.ALL;
// If we did not create placeholder tabs and are closing all tabs it is safe to just
// proceed. There are protections to prevent double closure already in place in TabModel
- // for the all tabs case.
+ // for the all tabs case. It is also safe to ignore `preventUndo` as these operations should
+ // always have an undo option.
if (!createdPlaceholders && isAllTabs) {
return params;
}
@@ -274,25 +301,15 @@
return TabClosureParams.closeTab(tabsToClose.get(0))
.recommendedNextTab(params.recommendedNextTab)
.uponExit(params.uponExit && !createdPlaceholders)
- .allowUndo(params.allowUndo)
+ .allowUndo(params.allowUndo && !preventUndo)
.withUndoRunnable(undoRunnable)
.build();
}
return TabClosureParams.closeTabs(tabsToClose)
- .allowUndo(params.allowUndo)
+ .allowUndo(params.allowUndo && !preventUndo)
.hideTabGroups(params.hideTabGroups)
.saveToTabRestoreService(params.saveToTabRestoreService)
.withUndoRunnable(undoRunnable)
.build();
}
-
- private static @NonNull Callback<Integer> adaptOnResultCallback(
- @NonNull Callback<Integer> callback, @Nullable TabModelActionListener listener) {
- return (result) -> {
- callback.onResult(result);
- if (listener != null) {
- listener.onConfirmationDialogResult(result);
- }
- };
- }
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabRemoverImplUnitTest.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabRemoverImplUnitTest.java
index 93aa7ff..51b4ecf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabRemoverImplUnitTest.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabRemoverImplUnitTest.java
@@ -34,6 +34,7 @@
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab_group_sync.TabGroupSyncServiceFactory;
+import org.chromium.chrome.browser.tabmodel.TabModelActionListener.DialogType;
import org.chromium.chrome.browser.tabmodel.TabModelRemover.TabModelRemoverFlowHandler;
import org.chromium.chrome.browser.tasks.tab_management.ActionConfirmationManager;
import org.chromium.chrome.test.util.browser.tabmodel.MockTabModel;
@@ -115,7 +116,9 @@
handler.performAction();
verify(mTabGroupModelFilter).closeTabs(eq(params));
- verify(mListener).onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ verify(mListener)
+ .onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
verifyNoMoreInteractions(mListener);
}
@@ -151,7 +154,9 @@
handler.showTabGroupDeletionConfirmationDialog(mOnResult);
verify(mActionConfirmationManager).processDeleteGroupAttempt(mOnResultCaptor.capture());
mOnResultCaptor.getValue().onResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
- verify(mListener).onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ verify(mListener)
+ .onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
verify(mOnResult).onResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
handler.performAction();
@@ -188,9 +193,11 @@
handler.showTabGroupDeletionConfirmationDialog(mOnResult);
verify(mActionConfirmationManager).processCloseTabAttempt(mOnResultCaptor.capture());
- mOnResultCaptor.getValue().onResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
- verify(mListener).onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
- verify(mOnResult).onResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ mOnResultCaptor.getValue().onResult(ActionConfirmationResult.CONFIRMATION_POSITIVE);
+ verify(mListener)
+ .onConfirmationDialogResult(
+ DialogType.SYNC, ActionConfirmationResult.CONFIRMATION_POSITIVE);
+ verify(mOnResult).onResult(ActionConfirmationResult.CONFIRMATION_POSITIVE);
handler.performAction();
verify(mTabGroupModelFilter).closeTabs(any(TabClosureParams.class));
@@ -231,7 +238,8 @@
.processCollaborationOwnerRemoveLastTab(eq(TITLE), mOnResultCaptor.capture());
mOnResultCaptor.getValue().onResult(ActionConfirmationResult.CONFIRMATION_POSITIVE);
verify(mListener)
- .onConfirmationDialogResult(ActionConfirmationResult.CONFIRMATION_POSITIVE);
+ .onConfirmationDialogResult(
+ DialogType.COLLABORATION, ActionConfirmationResult.CONFIRMATION_POSITIVE);
verify(mOnResult).onResult(ActionConfirmationResult.CONFIRMATION_POSITIVE);
handler.performAction();
@@ -273,7 +281,8 @@
.processCollaborationMemberRemoveLastTab(eq(TITLE), mOnResultCaptor.capture());
mOnResultCaptor.getValue().onResult(ActionConfirmationResult.CONFIRMATION_NEGATIVE);
verify(mListener)
- .onConfirmationDialogResult(ActionConfirmationResult.CONFIRMATION_NEGATIVE);
+ .onConfirmationDialogResult(
+ DialogType.COLLABORATION, ActionConfirmationResult.CONFIRMATION_NEGATIVE);
verify(mOnResult).onResult(ActionConfirmationResult.CONFIRMATION_NEGATIVE);
handler.performAction();
@@ -287,7 +296,7 @@
TabClosureParams params = TabClosureParams.closeAllTabs().build();
TabClosureParams newParams =
TabRemoverImpl.fixupTabClosureParams(
- mTabModel, params, /* placeholderTabs= */ null);
+ mTabModel, params, /* placeholderTabs= */ null, /* preventUndo= */ false);
assertEquals(params, newParams);
}
@@ -297,7 +306,8 @@
Tab tab1 = mTabModel.addTab(/* id= */ 1);
TabClosureParams params = TabClosureParams.closeAllTabs().build();
TabClosureParams newParams =
- TabRemoverImpl.fixupTabClosureParams(mTabModel, params, List.of(tab1));
+ TabRemoverImpl.fixupTabClosureParams(
+ mTabModel, params, List.of(tab1), /* preventUndo= */ false);
assertNotEquals(params, newParams);
assertFalse(newParams.isAllTabs);
assertEquals(List.of(tab0), newParams.tabs);
@@ -313,11 +323,26 @@
.build();
TabClosureParams newParams =
TabRemoverImpl.fixupTabClosureParams(
- mTabModel, params, /* placeholderTabs= */ null);
+ mTabModel, params, /* placeholderTabs= */ null, /* preventUndo= */ false);
assertEquals(params, newParams);
}
@Test
+ public void testUpdateTabClosureParams_NoPlaceholders_CloseTab_PreventUndo() {
+ Tab tab0 = mTabModel.addTab(/* id= */ 0);
+ TabClosureParams params =
+ TabClosureParams.closeTab(tab0)
+ .allowUndo(true)
+ .withUndoRunnable(mUndoRunnable)
+ .build();
+ TabClosureParams newParams =
+ TabRemoverImpl.fixupTabClosureParams(
+ mTabModel, params, /* placeholderTabs= */ null, /* preventUndo= */ true);
+ assertEquals(params.tabs, newParams.tabs);
+ assertFalse(newParams.allowUndo);
+ }
+
+ @Test
public void testUpdateTabClosureParams_Placeholder_CloseTab() {
Tab tab0 = mTabModel.addTab(/* id= */ 0);
Tab tab1 = mTabModel.addTab(/* id= */ 1);
@@ -328,7 +353,8 @@
.build();
List<Tab> placeholderTabs = List.of(tab1);
TabClosureParams newParams =
- TabRemoverImpl.fixupTabClosureParams(mTabModel, params, placeholderTabs);
+ TabRemoverImpl.fixupTabClosureParams(
+ mTabModel, params, placeholderTabs, /* preventUndo= */ false);
assertNotEquals(params, newParams);
assertEquals(params.tabCloseType, newParams.tabCloseType);
assertEquals(params.tabs, newParams.tabs);
@@ -356,11 +382,28 @@
.build();
TabClosureParams newParams =
TabRemoverImpl.fixupTabClosureParams(
- mTabModel, params, /* placeholderTabs= */ null);
+ mTabModel, params, /* placeholderTabs= */ null, /* preventUndo= */ false);
assertEquals(params, newParams);
}
@Test
+ public void testUpdateTabClosureParams_NoPlaceholders_CloseTabs_PreventUndo() {
+ mTabModel.addTab(/* id= */ 0);
+ Tab tab1 = mTabModel.addTab(/* id= */ 1);
+ TabClosureParams params =
+ TabClosureParams.closeTabs(List.of(tab1))
+ .allowUndo(true)
+ .hideTabGroups(true)
+ .withUndoRunnable(mUndoRunnable)
+ .build();
+ TabClosureParams newParams =
+ TabRemoverImpl.fixupTabClosureParams(
+ mTabModel, params, /* placeholderTabs= */ null, /* preventUndo= */ true);
+ assertEquals(params.tabs, newParams.tabs);
+ assertFalse(newParams.allowUndo);
+ }
+
+ @Test
public void testUpdateTabClosureParams_Placeholder_CloseTabs() {
Tab tab0 = mTabModel.addTab(/* id= */ 0);
Tab tab1 = mTabModel.addTab(/* id= */ 1);
@@ -372,7 +415,8 @@
.build();
List<Tab> placeholderTabs = List.of(tab2);
TabClosureParams newParams =
- TabRemoverImpl.fixupTabClosureParams(mTabModel, params, placeholderTabs);
+ TabRemoverImpl.fixupTabClosureParams(
+ mTabModel, params, placeholderTabs, /* preventUndo= */ false);
assertNotEquals(params, newParams);
assertEquals(params.tabCloseType, newParams.tabCloseType);
assertEquals(params.tabs, newParams.tabs);
@@ -417,7 +461,9 @@
handler.performAction();
verify(mTabModel).removeTab(tab0);
- verify(mListener).onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ verify(mListener)
+ .onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
verifyNoMoreInteractions(mListener);
}
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabUngrouperImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabUngrouperImpl.java
index 356ec7e..60025bae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabUngrouperImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabUngrouperImpl.java
@@ -16,6 +16,7 @@
import org.chromium.chrome.browser.data_sharing.DataSharingTabGroupUtils;
import org.chromium.chrome.browser.data_sharing.DataSharingTabGroupUtils.GroupsPendingDestroy;
import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabModelActionListener.DialogType;
import org.chromium.chrome.browser.tabmodel.TabModelRemover.TabModelRemoverFlowHandler;
import org.chromium.chrome.browser.tasks.tab_management.ActionConfirmationManager;
import org.chromium.components.browser_ui.widget.ActionConfirmationResult;
@@ -140,7 +141,7 @@
@Override
public void showTabGroupDeletionConfirmationDialog(@NonNull Callback<Integer> onResult) {
- var adaptedCallback = adaptOnResultCallback(onResult, takeListener());
+ var adaptedCallback = adaptOnResultCallback(onResult, DialogType.SYNC, takeListener());
if (mIsTabGroup) {
mActionConfirmationManager.processUngroupAttempt(adaptedCallback);
} else {
@@ -151,12 +152,14 @@
@Override
public void showCollaborationKeepDialog(
@MemberRole int memberRole, @NonNull String title, Callback<Integer> onResult) {
+ var adaptedCallback =
+ adaptOnResultCallback(onResult, DialogType.COLLABORATION, takeListener());
if (memberRole == MemberRole.OWNER) {
mActionConfirmationManager.processCollaborationOwnerRemoveLastTab(
- title, adaptOnResultCallback(onResult, takeListener()));
+ title, adaptedCallback);
} else if (memberRole == MemberRole.MEMBER) {
mActionConfirmationManager.processCollaborationMemberRemoveLastTab(
- title, adaptOnResultCallback(onResult, takeListener()));
+ title, adaptedCallback);
} else {
assert false : "Not reached";
}
@@ -175,7 +178,8 @@
PassthroughTabUngrouper.doUngroupTabs(filter, newTabsToUngroup, mTrailing);
if (mListener != null) {
- mListener.onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ mListener.onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
}
}
@@ -187,11 +191,18 @@
}
private static @NonNull Callback<Integer> adaptOnResultCallback(
- @NonNull Callback<Integer> callback, @Nullable TabModelActionListener listener) {
+ @NonNull Callback<Integer> callback,
+ @DialogType int plannedDialogType,
+ @Nullable TabModelActionListener listener) {
return (result) -> {
callback.onResult(result);
if (listener != null) {
- listener.onConfirmationDialogResult(result);
+ @DialogType
+ int dialogType =
+ result == ActionConfirmationResult.IMMEDIATE_CONTINUE
+ ? DialogType.NONE
+ : plannedDialogType;
+ listener.onConfirmationDialogResult(dialogType, result);
}
};
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabUngrouperImplUnitTest.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabUngrouperImplUnitTest.java
index a280364..35f0789b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabUngrouperImplUnitTest.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabUngrouperImplUnitTest.java
@@ -29,6 +29,7 @@
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab_group_sync.TabGroupSyncServiceFactory;
+import org.chromium.chrome.browser.tabmodel.TabModelActionListener.DialogType;
import org.chromium.chrome.browser.tabmodel.TabModelRemover.TabModelRemoverFlowHandler;
import org.chromium.chrome.browser.tasks.tab_management.ActionConfirmationManager;
import org.chromium.chrome.test.util.browser.tabmodel.MockTabModel;
@@ -102,12 +103,14 @@
handler.performAction();
verify(mTabGroupModelFilter)
.moveTabOutOfGroupInDirection(tab0.getId(), /* trailing= */ true);
- verify(mListener).onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ verify(mListener)
+ .onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
verifyNoMoreInteractions(mListener);
}
@Test
- public void testUngroupTabsHandler_UngroupTabGroup_RootId_DestructionOnly() {
+ public void testUngroupTabsHandler_UngroupTabGroup_RootId_DestructionOnly_ImmediateContinue() {
int id = 0;
Tab tab0 = mTabModel.addTab(id);
tab0.setTabGroupId(TAB_GROUP_ID.tabGroupId);
@@ -138,7 +141,9 @@
handler.showTabGroupDeletionConfirmationDialog(mOnResult);
verify(mActionConfirmationManager).processUngroupAttempt(mOnResultCaptor.capture());
mOnResultCaptor.getValue().onResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
- verify(mListener).onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ verify(mListener)
+ .onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
verify(mOnResult).onResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
handler.performAction();
@@ -148,6 +153,50 @@
}
@Test
+ public void
+ testUngroupTabsHandler_UngroupTabGroup_RootId_DestructionOnly_ConfirmationPositive() {
+ int id = 0;
+ Tab tab0 = mTabModel.addTab(id);
+ tab0.setTabGroupId(TAB_GROUP_ID.tabGroupId);
+ tab0.setRootId(id);
+ when(mTabGroupModelFilter.getRelatedTabListForRootId(id)).thenReturn(List.of(tab0));
+ when(mTabGroupModelFilter.isTabInTabGroup(tab0)).thenReturn(true);
+
+ mTabUngrouperImpl.ungroupTabGroup(
+ id, /* trailing= */ true, /* allowDialog= */ true, mListener);
+ verify(mTabModelRemover).doTabRemovalFlow(mHandlerCaptor.capture(), eq(true));
+ TabModelRemoverFlowHandler handler = mHandlerCaptor.getValue();
+
+ SavedTabGroupTab savedTab = new SavedTabGroupTab();
+ savedTab.localId = id;
+ SavedTabGroup savedTabGroup = new SavedTabGroup();
+ savedTabGroup.localId = TAB_GROUP_ID;
+ savedTabGroup.savedTabs.add(savedTab);
+ when(mTabGroupSyncService.getAllGroupIds()).thenReturn(new String[] {SYNC_ID});
+ when(mTabGroupSyncService.getGroup(SYNC_ID)).thenReturn(savedTabGroup);
+
+ GroupsPendingDestroy groupsPendingDestroy = handler.computeGroupsPendingDestroy();
+ assertFalse(groupsPendingDestroy.isEmpty());
+ assertTrue(groupsPendingDestroy.collaborationGroupsDestroyed.isEmpty());
+ assertFalse(groupsPendingDestroy.syncedGroupsDestroyed.isEmpty());
+
+ // No placeholder tabs created.
+
+ handler.showTabGroupDeletionConfirmationDialog(mOnResult);
+ verify(mActionConfirmationManager).processUngroupAttempt(mOnResultCaptor.capture());
+ mOnResultCaptor.getValue().onResult(ActionConfirmationResult.CONFIRMATION_POSITIVE);
+ verify(mListener)
+ .onConfirmationDialogResult(
+ DialogType.SYNC, ActionConfirmationResult.CONFIRMATION_POSITIVE);
+ verify(mOnResult).onResult(ActionConfirmationResult.CONFIRMATION_POSITIVE);
+
+ handler.performAction();
+ verify(mTabGroupModelFilter).moveTabOutOfGroupInDirection(id, /* trailing= */ true);
+
+ verifyNoMoreInteractions(mListener);
+ }
+
+ @Test
public void testUngroupTabsHandler_UngroupTabGroup_TabGroupId_DestructionOnly() {
int id = 0;
Tab tab0 = mTabModel.addTab(id);
@@ -181,7 +230,9 @@
handler.showTabGroupDeletionConfirmationDialog(mOnResult);
verify(mActionConfirmationManager).processUngroupAttempt(mOnResultCaptor.capture());
mOnResultCaptor.getValue().onResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
- verify(mListener).onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ verify(mListener)
+ .onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
verify(mOnResult).onResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
handler.performAction();
@@ -220,7 +271,9 @@
handler.showTabGroupDeletionConfirmationDialog(mOnResult);
verify(mActionConfirmationManager).processUngroupTabAttempt(mOnResultCaptor.capture());
mOnResultCaptor.getValue().onResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
- verify(mListener).onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ verify(mListener)
+ .onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
verify(mOnResult).onResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
handler.performAction();
@@ -263,7 +316,8 @@
.processCollaborationOwnerRemoveLastTab(eq(TITLE), mOnResultCaptor.capture());
mOnResultCaptor.getValue().onResult(ActionConfirmationResult.CONFIRMATION_POSITIVE);
verify(mListener)
- .onConfirmationDialogResult(ActionConfirmationResult.CONFIRMATION_POSITIVE);
+ .onConfirmationDialogResult(
+ DialogType.COLLABORATION, ActionConfirmationResult.CONFIRMATION_POSITIVE);
verify(mOnResult).onResult(ActionConfirmationResult.CONFIRMATION_POSITIVE);
handler.performAction();
@@ -306,7 +360,8 @@
.processCollaborationMemberRemoveLastTab(eq(TITLE), mOnResultCaptor.capture());
mOnResultCaptor.getValue().onResult(ActionConfirmationResult.CONFIRMATION_NEGATIVE);
verify(mListener)
- .onConfirmationDialogResult(ActionConfirmationResult.CONFIRMATION_NEGATIVE);
+ .onConfirmationDialogResult(
+ DialogType.COLLABORATION, ActionConfirmationResult.CONFIRMATION_NEGATIVE);
verify(mOnResult).onResult(ActionConfirmationResult.CONFIRMATION_NEGATIVE);
handler.performAction();
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/PassthroughTabRemover.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/PassthroughTabRemover.java
index 9fd6c94..af5f1d44 100644
--- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/PassthroughTabRemover.java
+++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/PassthroughTabRemover.java
@@ -10,6 +10,7 @@
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabModelActionListener.DialogType;
import org.chromium.components.browser_ui.widget.ActionConfirmationResult;
/**
@@ -35,7 +36,8 @@
@Nullable TabModelActionListener listener) {
forceCloseTabs(tabClosureParams);
if (listener != null) {
- listener.onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ listener.onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
}
}
@@ -51,7 +53,8 @@
assert mTabGroupModelFilterSupplier.hasValue();
doRemoveTab(mTabGroupModelFilterSupplier.get().getTabModel(), tab);
if (listener != null) {
- listener.onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ listener.onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
}
}
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/PassthroughTabUngrouper.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/PassthroughTabUngrouper.java
index b8f16c1..63dc876 100644
--- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/PassthroughTabUngrouper.java
+++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/PassthroughTabUngrouper.java
@@ -11,6 +11,7 @@
import org.chromium.base.Token;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabModelActionListener.DialogType;
import org.chromium.components.browser_ui.widget.ActionConfirmationResult;
import java.util.List;
@@ -77,7 +78,8 @@
doUngroupTabs(filter, tabs, trailing);
if (listener != null) {
- listener.onConfirmationDialogResult(ActionConfirmationResult.IMMEDIATE_CONTINUE);
+ listener.onConfirmationDialogResult(
+ DialogType.NONE, ActionConfirmationResult.IMMEDIATE_CONTINUE);
}
}
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelActionListener.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelActionListener.java
index ffe82cb..cc9e0f9 100644
--- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelActionListener.java
+++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelActionListener.java
@@ -4,19 +4,40 @@
package org.chromium.chrome.browser.tabmodel;
+import androidx.annotation.IntDef;
+
import org.chromium.components.browser_ui.widget.ActionConfirmationResult;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Listener to get updates for actions that may show speedbump dialogs when performing operations on
* a {@link TabModel}. See {@link TabRemover} and {@link TabUngrouper}.
*/
public interface TabModelActionListener {
+ /** An enum representing the type of dialog that was shown. */
+ @IntDef({DialogType.NONE, DialogType.SYNC, DialogType.COLLABORATION})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DialogType {
+ /** No dialog was shown. */
+ int NONE = 0;
+
+ /** A dialog about synced group destruction was shown. */
+ int SYNC = 1;
+
+ /** A dialog about collaboration destruction was shown. */
+ int COLLABORATION = 2;
+ }
+
/**
* Called with the result of showing the action confirmation dialog for the action. This is
* guaranteed to be called, and may be called synchronously if no dialog is shown and the action
* will proceed synchronously. This will be called after the action is triggered.
*
+ * @param dialogType The type of dialog that was shown.
* @param result The {@link ActionConfirmationResult}.
*/
- default void onConfirmationDialogResult(@ActionConfirmationResult int result) {}
+ default void onConfirmationDialogResult(
+ @DialogType int dialogType, @ActionConfirmationResult int result) {}
}