Set the restored most recently closed tab as current tab.
On other desktop platforms(linux, mac, chromeos,etc), when user uses keyboard shortcut "ctrl-shift-t" to re-open the most recently closed tab, after the tab is restored, it is set as the current tab. On Clank, however, the restored tab is inactive. This makes the user experience inconsistent on clank. This cl fixes this issue by always setting the tab(most recently closed) restored as the current tab. This cl fixes the case for restoring a tab without snackbar showing up, i.e. from tab restore service. Bug: 348478081 Change-Id: I912143efb508a6ab4bec4cfd50e37eb3d6a964c1 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5669932 Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com> Reviewed-by: Nico Weber <thakis@chromium.org> Reviewed-by: Scott Violet <sky@chromium.org> Reviewed-by: Calder Kitagawa <ckitagawa@chromium.org> Reviewed-by: David Roger <droger@chromium.org> Commit-Queue: Jenny Zhang <jennyz@chromium.org> Cr-Commit-Position: refs/heads/main@{#1332509}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
da10677dc7
commit
5d08744a14
chrome
android
java
src
org
chromium
javatests
src
org
chromium
chrome
browser
browser
android
auxiliary_search
persisted_tab_data
browsing_data
metrics
sessions
tabpersistence
android
java
src
org
chromium
chrome
browser
tabpersistence
ui
components/sessions/core
ios/chrome/browser/sessions/model
tools/metrics/histograms/metadata/android
@ -2959,6 +2959,7 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
|
||||
|| type == TabLaunchType.FROM_LONGPRESS_BACKGROUND
|
||||
|| type == TabLaunchType.FROM_LONGPRESS_BACKGROUND_IN_GROUP
|
||||
|| type == TabLaunchType.FROM_RECENT_TABS
|
||||
|| type == TabLaunchType.FROM_RECENT_TABS_FOREGROUND
|
||||
|| (type == TabLaunchType.FROM_RESTORE && tab.getParentId() != Tab.INVALID_TAB_ID);
|
||||
}
|
||||
|
||||
|
@ -135,6 +135,8 @@ public class ChromeTabCreator extends TabCreator {
|
||||
return "Unset";
|
||||
case TabLaunchType.FROM_SYNC_BACKGROUND:
|
||||
return "SyncBackground";
|
||||
case TabLaunchType.FROM_RECENT_TABS_FOREGROUND:
|
||||
return "RecentTabsForeground";
|
||||
default:
|
||||
assert false : "Unexpected serialization of tabLaunchType: " + tabLaunchType;
|
||||
return "TypeUnknown";
|
||||
@ -651,6 +653,7 @@ public class ChromeTabCreator extends TabCreator {
|
||||
case TabLaunchType.FROM_LONGPRESS_BACKGROUND:
|
||||
case TabLaunchType.FROM_LONGPRESS_BACKGROUND_IN_GROUP:
|
||||
case TabLaunchType.FROM_RECENT_TABS:
|
||||
case TabLaunchType.FROM_RECENT_TABS_FOREGROUND:
|
||||
// On low end devices tabs are backgrounded in a frozen state, so we set the
|
||||
// transition type to RELOAD to avoid handling intents when the tab is foregrounded.
|
||||
// (https://crbug.com/758027)
|
||||
|
@ -858,9 +858,14 @@ public class TabModelImpl extends TabModelJniBridge {
|
||||
/** Used to restore tabs from native. */
|
||||
@Override
|
||||
protected boolean createTabWithWebContents(
|
||||
Tab parent, Profile profile, WebContents webContents) {
|
||||
Tab parent, Profile profile, WebContents webContents, boolean select) {
|
||||
return getTabCreator(profile.isOffTheRecord())
|
||||
.createTabWithWebContents(parent, webContents, TabLaunchType.FROM_RECENT_TABS);
|
||||
.createTabWithWebContents(
|
||||
parent,
|
||||
webContents,
|
||||
select
|
||||
? TabLaunchType.FROM_RECENT_TABS_FOREGROUND
|
||||
: TabLaunchType.FROM_RECENT_TABS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -155,11 +155,12 @@ public abstract class TabModelJniBridge implements TabModel {
|
||||
* @param parent The parent tab that creates the new tab.
|
||||
* @param profile The profile for which to create the new tab.
|
||||
* @param webContents A {@link WebContents} object.
|
||||
* @param select Select the created tab.
|
||||
* @return Whether or not the Tab was successfully created.
|
||||
*/
|
||||
@CalledByNative
|
||||
protected abstract boolean createTabWithWebContents(
|
||||
Tab parent, Profile profile, WebContents webContents);
|
||||
Tab parent, Profile profile, WebContents webContents, boolean select);
|
||||
|
||||
@CalledByNative
|
||||
protected abstract void openNewTab(
|
||||
|
@ -127,10 +127,10 @@ public class RecentlyClosedBridgeTest {
|
||||
});
|
||||
}
|
||||
|
||||
/** Tests opening the most recently closed tab in the background. */
|
||||
/** Tests opening the most recently closed tab in the foreground. */
|
||||
@Test
|
||||
@MediumTest
|
||||
public void testOpenMostRecentlyClosedEntry_Tab_InBackground() {
|
||||
public void testOpenMostRecentlyClosedEntry_Tab_InForeground() {
|
||||
final String[] urls = new String[] {getUrl(TEST_PAGE_A), getUrl(TEST_PAGE_B)};
|
||||
final Tab tabA = sActivityTestRule.loadUrlInNewTab(urls[0], /* incognito= */ false);
|
||||
final Tab tabB = sActivityTestRule.loadUrlInNewTab(urls[1], /* incognito= */ false);
|
||||
@ -170,8 +170,8 @@ public class RecentlyClosedBridgeTest {
|
||||
Assert.assertEquals(urls[0], ChromeTabUtils.getUrlOnUiThread(tabs.get(1)).getSpec());
|
||||
ThreadUtils.runOnUiThreadBlocking(
|
||||
() -> {
|
||||
// No Renderer for background tabA.
|
||||
Assert.assertNull(tabs.get(1).getWebContents().getRenderWidgetHostView());
|
||||
// tabA is launched in foreground.
|
||||
Assert.assertNotNull(tabs.get(1).getWebContents().getRenderWidgetHostView());
|
||||
});
|
||||
}
|
||||
|
||||
@ -1440,6 +1440,112 @@ public class RecentlyClosedBridgeTest {
|
||||
Assert.assertEquals(0, recentEntries.size());
|
||||
}
|
||||
|
||||
/** Tests closing a tab will be saved as a TAB session entry in tab restore service. */
|
||||
@Test
|
||||
@MediumTest
|
||||
public void testCloseTabSaveAsTabSessionRestoreEntry() {
|
||||
final String[] urls = new String[] {getUrl(TEST_PAGE_A)};
|
||||
final Tab tabA = sActivityTestRule.loadUrlInNewTab(urls[0], /* incognito= */ false);
|
||||
|
||||
final String[] titles = new String[1];
|
||||
ThreadUtils.runOnUiThreadBlocking(
|
||||
() -> {
|
||||
titles[0] = tabA.getTitle();
|
||||
mTabModel.closeTab(tabA, false, true);
|
||||
mTabModel.commitTabClosure(tabA.getId());
|
||||
});
|
||||
final List<RecentlyClosedEntry> recentEntries = new ArrayList();
|
||||
ThreadUtils.runOnUiThreadBlocking(
|
||||
() -> {
|
||||
recentEntries.addAll(
|
||||
mRecentlyClosedBridge.getRecentlyClosedEntries(MAX_ENTRY_COUNT));
|
||||
});
|
||||
Assert.assertEquals(1, recentEntries.size());
|
||||
RecentlyClosedEntry recentEntry = recentEntries.get(0);
|
||||
// Verify recentEntry is from a TAB session entry returned by tab restore service.
|
||||
// Note: RecentlyClosedBridgeJni.getRecentlyClosedEntries returns a RecentlyClosedTab
|
||||
// instance for a session entry of type sessions::tab_restore::Type::TAB.
|
||||
Assert.assertTrue(RecentlyClosedTab.class.isInstance(recentEntry));
|
||||
final List<RecentlyClosedTab> recentTabs =
|
||||
(List<RecentlyClosedTab>) (List<? extends RecentlyClosedEntry>) recentEntries;
|
||||
Assert.assertEquals(1, recentTabs.size());
|
||||
assertTabsAre(recentTabs, titles, urls);
|
||||
}
|
||||
|
||||
/** Tests closing all tabs will be saved as a WINDOW session entry in tab restore service. */
|
||||
@Test
|
||||
@MediumTest
|
||||
public void testCloseAllTabsSaveAsWindowSessionRestoreEntry() {
|
||||
// Tab order is inverted in RecentlyClosedEntry as most recent comes first so log data in
|
||||
// reverse.
|
||||
final String[] urls = new String[] {getUrl(TEST_PAGE_B), getUrl(TEST_PAGE_A)};
|
||||
final Tab tabA = sActivityTestRule.loadUrlInNewTab(urls[1], /* incognito= */ false);
|
||||
final Tab tabB = sActivityTestRule.loadUrlInNewTab(urls[0], /* incognito= */ false);
|
||||
|
||||
final String[] titles = new String[2];
|
||||
ThreadUtils.runOnUiThreadBlocking(
|
||||
() -> {
|
||||
titles[1] = tabA.getTitle();
|
||||
titles[0] = tabB.getTitle();
|
||||
mTabModel.closeAllTabs(/* uponExit= */ false);
|
||||
mTabModel.commitAllTabClosures();
|
||||
});
|
||||
final List<RecentlyClosedEntry> recentEntries = new ArrayList<>();
|
||||
ThreadUtils.runOnUiThreadBlocking(
|
||||
() -> {
|
||||
recentEntries.addAll(
|
||||
mRecentlyClosedBridge.getRecentlyClosedEntries(MAX_ENTRY_COUNT));
|
||||
});
|
||||
Assert.assertEquals(1, recentEntries.size());
|
||||
RecentlyClosedEntry recentEntry = recentEntries.get(0);
|
||||
// Verify recentEntry is from a WINDOW session entry returned by tab restore service.
|
||||
// Note: RecentlyClosedBridgeJni.getRecentlyClosedEntries returns a RecentlyClosedBulkEvent
|
||||
// instance for a session entry of type sessions::tab_restore::Type::WINDOW.
|
||||
Assert.assertTrue(RecentlyClosedBulkEvent.class.isInstance(recentEntry));
|
||||
final RecentlyClosedBulkEvent event = (RecentlyClosedBulkEvent) recentEntry;
|
||||
final List<RecentlyClosedTab> recentTabs = event.getTabs();
|
||||
Assert.assertEquals(2, recentTabs.size());
|
||||
assertTabsAre(recentTabs, titles, urls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests closing multiple tabs will be saved as a WINDOW session entry in tab restore service.
|
||||
*/
|
||||
@Test
|
||||
@MediumTest
|
||||
public void testCloseMultipleTabsSaveAsWindowSessionRestoreEntry() {
|
||||
// Tab order is inverted in RecentlyClosedEntry as most recent comes first so log data in
|
||||
// reverse.
|
||||
final String[] urls = new String[] {getUrl(TEST_PAGE_B), getUrl(TEST_PAGE_A)};
|
||||
final Tab tabA = sActivityTestRule.loadUrlInNewTab(urls[1], /* incognito= */ false);
|
||||
final Tab tabB = sActivityTestRule.loadUrlInNewTab(urls[0], /* incognito= */ false);
|
||||
|
||||
final String[] titles = new String[2];
|
||||
final int[] tabCountBeforeClosingTabs = new int[1];
|
||||
ThreadUtils.runOnUiThreadBlocking(
|
||||
() -> {
|
||||
titles[1] = tabA.getTitle();
|
||||
titles[0] = tabB.getTitle();
|
||||
tabCountBeforeClosingTabs[0] = mTabModel.getCount();
|
||||
mTabModel.closeMultipleTabs(Arrays.asList(new Tab[] {tabA, tabB}), true);
|
||||
mTabModel.commitAllTabClosures();
|
||||
});
|
||||
final List<RecentlyClosedEntry> recentEntries = new ArrayList<>();
|
||||
final int tabCountAfterClosingTabs = getRecentEntriesAndReturnActiveTabCount(recentEntries);
|
||||
Assert.assertEquals(3, tabCountBeforeClosingTabs[0]);
|
||||
Assert.assertEquals(1, tabCountAfterClosingTabs);
|
||||
Assert.assertEquals(1, recentEntries.size());
|
||||
RecentlyClosedEntry recentEntry = recentEntries.get(0);
|
||||
// Verify recentEntry is from a WINDOW session entry returned by tab restore service.
|
||||
// Note: RecentlyClosedBridgeJni.getRecentlyClosedEntries returns a RecentlyClosedBulkEvent
|
||||
// instance for a session entry of type sessions::tab_restore::Type::WINDOW.
|
||||
Assert.assertTrue(RecentlyClosedBulkEvent.class.isInstance(recentEntry));
|
||||
final RecentlyClosedBulkEvent event = (RecentlyClosedBulkEvent) recentEntry;
|
||||
final List<RecentlyClosedTab> recentTabs = event.getTabs();
|
||||
Assert.assertEquals(2, recentTabs.size());
|
||||
assertTabsAre(recentTabs, titles, urls);
|
||||
}
|
||||
|
||||
// TODO(crbug.com/40218713): Add a test a case where bulk closures remain in the native service,
|
||||
// but the flag state is flipped.
|
||||
|
||||
|
@ -267,7 +267,7 @@ public class UndoTabModelTest {
|
||||
Tab tab1 = model.getTabAt(1);
|
||||
tabs = new Tab[] {tab0, tab1};
|
||||
Assert.assertEquals(TEST_URL_0, ChromeTabUtils.getUrlStringOnUiThread(tab1));
|
||||
checkState(model, tabs, tab0, EMPTY, tabs, tab0);
|
||||
checkState(model, tabs, tab1, EMPTY, tabs, tab1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -338,14 +338,19 @@ public class UndoTabModelTest {
|
||||
Tab[] firstWindowTabs = new Tab[] {firstModelTab, firstModel.getTabAt(1)};
|
||||
Tab[] secondWindowTabs = new Tab[] {secondModelTab, secondModel.getTabAt(1)};
|
||||
checkState(
|
||||
firstModel, firstWindowTabs, firstModelTab, EMPTY, firstWindowTabs, firstModelTab);
|
||||
firstModel,
|
||||
firstWindowTabs,
|
||||
firstModel.getTabAt(1),
|
||||
EMPTY,
|
||||
firstWindowTabs,
|
||||
firstModel.getTabAt(1));
|
||||
checkState(
|
||||
secondModel,
|
||||
secondWindowTabs,
|
||||
secondModelTab,
|
||||
secondModel.getTabAt(1),
|
||||
EMPTY,
|
||||
secondWindowTabs,
|
||||
secondModelTab);
|
||||
secondModel.getTabAt(1));
|
||||
Assert.assertEquals(TEST_URL_0, ChromeTabUtils.getUrlStringOnUiThread(firstWindowTabs[1]));
|
||||
Assert.assertEquals(TEST_URL_1, ChromeTabUtils.getUrlStringOnUiThread(secondWindowTabs[1]));
|
||||
|
||||
@ -413,7 +418,8 @@ public class UndoTabModelTest {
|
||||
Tab tab0 = firstModel.getTabAt(0);
|
||||
Tab tab1 = firstModel.getTabAt(1);
|
||||
Tab[] firstWindowTabs = new Tab[] {tab0, tab1};
|
||||
checkState(firstModel, firstWindowTabs, tab0, EMPTY, firstWindowTabs, tab0);
|
||||
// After restoring tab1, it should selected as the current tab.
|
||||
checkState(firstModel, firstWindowTabs, tab1, EMPTY, firstWindowTabs, tab1);
|
||||
Assert.assertEquals(TEST_URL_1, ChromeTabUtils.getUrlStringOnUiThread(tab1));
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ IN_PROC_BROWSER_TEST_F(AuxiliarySearchProviderBrowserTest,
|
||||
std::unique_ptr<content::WebContents> contents = content::WebContents::Create(
|
||||
content::WebContents::CreateParams(profile()));
|
||||
content::WebContents* second_web_contents = contents.release();
|
||||
tab_model->CreateTab(second_tab, second_web_contents);
|
||||
tab_model->CreateTab(second_tab, second_web_contents, /*select=*/true);
|
||||
std::unique_ptr<SensitivityPersistedTabDataAndroid> sptda2 =
|
||||
std::make_unique<SensitivityPersistedTabDataAndroid>(second_tab);
|
||||
sptda2->set_is_sensitive(false);
|
||||
@ -138,7 +138,7 @@ IN_PROC_BROWSER_TEST_F(AuxiliarySearchProviderBrowserTest,
|
||||
std::unique_ptr<content::WebContents> contents = content::WebContents::Create(
|
||||
content::WebContents::CreateParams(profile()));
|
||||
content::WebContents* second_web_contents = contents.release();
|
||||
tab_model->CreateTab(second_tab, second_web_contents);
|
||||
tab_model->CreateTab(second_tab, second_web_contents, /*select=*/true);
|
||||
std::unique_ptr<SensitivityPersistedTabDataAndroid> sptda2 =
|
||||
std::make_unique<SensitivityPersistedTabDataAndroid>(second_tab);
|
||||
sptda2->set_is_sensitive(false);
|
||||
@ -148,7 +148,7 @@ IN_PROC_BROWSER_TEST_F(AuxiliarySearchProviderBrowserTest,
|
||||
contents = content::WebContents::Create(
|
||||
content::WebContents::CreateParams(profile()));
|
||||
content::WebContents* third_web_contents = contents.release();
|
||||
tab_model->CreateTab(third_tab, third_web_contents);
|
||||
tab_model->CreateTab(third_tab, third_web_contents, /*select=*/true);
|
||||
std::unique_ptr<SensitivityPersistedTabDataAndroid> sptda3 =
|
||||
std::make_unique<SensitivityPersistedTabDataAndroid>(third_tab);
|
||||
sptda3->set_is_sensitive(false);
|
||||
|
@ -2,9 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/android/persisted_tab_data/persisted_tab_data_android.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "chrome/browser/android/persisted_tab_data/persisted_tab_data_android.h"
|
||||
#include "chrome/browser/android/persisted_tab_data/test/bar_persisted_tab_data.h"
|
||||
#include "chrome/browser/android/persisted_tab_data/test/foo_persisted_tab_data.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
@ -35,11 +36,13 @@ class PersistedTabDataAndroidBrowserTest : public AndroidBrowserTest {
|
||||
// Create a second Tab.
|
||||
TabModel* tab_model =
|
||||
TabModelList::GetTabModelForWebContents(web_contents());
|
||||
ASSERT_EQ(1, tab_model->GetTabCount());
|
||||
std::unique_ptr<content::WebContents> contents =
|
||||
content::WebContents::Create(
|
||||
content::WebContents::CreateParams(profile()));
|
||||
content::WebContents* second_web_contents = contents.release();
|
||||
tab_model->CreateTab(tab_android(), second_web_contents);
|
||||
tab_model->CreateTab(tab_android(), second_web_contents, /*select=*/true);
|
||||
ASSERT_EQ(2, tab_model->GetTabCount());
|
||||
}
|
||||
|
||||
TabAndroid* tab_android() {
|
||||
@ -49,7 +52,8 @@ class PersistedTabDataAndroidBrowserTest : public AndroidBrowserTest {
|
||||
TabAndroid* another_tab() {
|
||||
TabModel* tab_model =
|
||||
TabModelList::GetTabModelForWebContents(web_contents());
|
||||
return tab_model->GetTabAt(1);
|
||||
int another_tab_index = tab_model->GetTabAt(0) == tab_android() ? 1 : 0;
|
||||
return tab_model->GetTabAt(another_tab_index);
|
||||
}
|
||||
|
||||
void FooExistsForTesting(TabAndroid* tab_android,
|
||||
|
@ -353,7 +353,7 @@ IN_PROC_BROWSER_TEST_P(ChromeBrowsingDataLifetimeManagerScheduledRemovalTest,
|
||||
std::unique_ptr<content::WebContents> contents = content::WebContents::Create(
|
||||
content::WebContents::CreateParams(GetProfile()));
|
||||
auto* second_tab = contents.release();
|
||||
tab_model->CreateTab(current_tab, second_tab);
|
||||
tab_model->CreateTab(current_tab, second_tab, /*select=*/true);
|
||||
ASSERT_TRUE(content::NavigateToURL(second_tab, url));
|
||||
#endif
|
||||
DCHECK_NE(first_tab, second_tab);
|
||||
|
@ -186,7 +186,8 @@ class TestTabModel : public TabModel {
|
||||
void SetActiveIndex(int index) override {}
|
||||
void CloseTabAt(int index) override {}
|
||||
void CreateTab(TabAndroid* parent,
|
||||
content::WebContents* web_contents) override {}
|
||||
content::WebContents* web_contents,
|
||||
bool select) override {}
|
||||
void HandlePopupNavigation(TabAndroid* parent,
|
||||
NavigateParams* params) override {}
|
||||
content::WebContents* CreateNewTabForDevTools(const GURL& url) override {
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "content/public/browser/restore_type.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
#include "ui/base/window_open_disposition.h"
|
||||
|
||||
// The android implementation does not do anything "foreign session" specific.
|
||||
// We use it to restore tabs from "recently closed" too.
|
||||
@ -61,7 +62,9 @@ content::WebContents* SessionRestore::RestoreForeignSessionTab(
|
||||
}
|
||||
DCHECK(disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB ||
|
||||
disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB);
|
||||
tab_model->CreateTab(current_tab, new_web_contents.release());
|
||||
tab_model->CreateTab(
|
||||
current_tab, new_web_contents.release(),
|
||||
disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB);
|
||||
return raw_new_web_contents;
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,10 @@ class MockLiveTabContext : public sessions::LiveTabContext {
|
||||
MOCK_CONST_METHOD0(GetWorkspace, std::string());
|
||||
MOCK_METHOD(sessions::LiveTab*,
|
||||
AddRestoredTab,
|
||||
((const sessions::tab_restore::Tab&), int, bool),
|
||||
((const sessions::tab_restore::Tab&),
|
||||
int,
|
||||
bool,
|
||||
sessions::tab_restore::Type),
|
||||
(override));
|
||||
MOCK_METHOD(sessions::LiveTab*,
|
||||
ReplaceRestoredTab,
|
||||
|
@ -211,6 +211,8 @@ public class FlatBufferTabStateSerializer implements TabStateSerializer {
|
||||
return TabLaunchType.UNSET;
|
||||
case TabLaunchTypeAtCreation.FROM_SYNC_BACKGROUND:
|
||||
return TabLaunchType.FROM_SYNC_BACKGROUND;
|
||||
case TabLaunchTypeAtCreation.FROM_RECENT_TABS_FOREGROUND:
|
||||
return TabLaunchType.FROM_RECENT_TABS_FOREGROUND;
|
||||
case TabLaunchTypeAtCreation.SIZE:
|
||||
return TabLaunchType.SIZE;
|
||||
case TabLaunchTypeAtCreation.UNKNOWN:
|
||||
@ -278,6 +280,8 @@ public class FlatBufferTabStateSerializer implements TabStateSerializer {
|
||||
return TabLaunchTypeAtCreation.UNSET;
|
||||
case TabLaunchType.FROM_SYNC_BACKGROUND:
|
||||
return TabLaunchTypeAtCreation.FROM_SYNC_BACKGROUND;
|
||||
case TabLaunchType.FROM_RECENT_TABS_FOREGROUND:
|
||||
return TabLaunchTypeAtCreation.FROM_RECENT_TABS_FOREGROUND;
|
||||
case TabLaunchType.SIZE:
|
||||
return TabLaunchTypeAtCreation.SIZE;
|
||||
default:
|
||||
|
@ -145,12 +145,13 @@ public class TabStateFileManagerUnitTest {
|
||||
Assert.assertEquals(21, TabLaunchTypeAtCreation.FROM_OMNIBOX);
|
||||
Assert.assertEquals(22, TabLaunchTypeAtCreation.UNSET);
|
||||
Assert.assertEquals(23, TabLaunchTypeAtCreation.FROM_SYNC_BACKGROUND);
|
||||
Assert.assertEquals(24, TabLaunchTypeAtCreation.FROM_RECENT_TABS_FOREGROUND);
|
||||
// Note this should be the total number of TabLaunchTypeAtCreation values including
|
||||
// SIZE and UNKNOWN so it should be equal to the last value +3.
|
||||
Assert.assertEquals(
|
||||
"Need to increment 1 to expected value each time a LaunchTypeAtCreation "
|
||||
+ "is added. Also need to add any new LaunchTypeAtCreation to this test.",
|
||||
26,
|
||||
27,
|
||||
TabLaunchTypeAtCreation.names.length);
|
||||
}
|
||||
|
||||
@ -161,7 +162,7 @@ public class TabStateFileManagerUnitTest {
|
||||
+ " FlatBufferTabStateSerizer#getLaunchTypeFromFlatBuffer,"
|
||||
+ " FlatBufferTabStateSerizer#getLaunchTypeToFlatBuffer"
|
||||
+ " and this test file.",
|
||||
24,
|
||||
25,
|
||||
TabLaunchType.SIZE);
|
||||
}
|
||||
|
||||
@ -279,6 +280,10 @@ public class TabStateFileManagerUnitTest {
|
||||
(Integer) TabLaunchType.FROM_SYNC_BACKGROUND,
|
||||
FlatBufferTabStateSerializer.getLaunchTypeFromFlatBuffer(
|
||||
TabLaunchTypeAtCreation.FROM_SYNC_BACKGROUND));
|
||||
Assert.assertEquals(
|
||||
(Integer) TabLaunchType.FROM_RECENT_TABS_FOREGROUND,
|
||||
FlatBufferTabStateSerializer.getLaunchTypeFromFlatBuffer(
|
||||
TabLaunchTypeAtCreation.FROM_RECENT_TABS_FOREGROUND));
|
||||
Assert.assertEquals(
|
||||
(Integer) TabLaunchType.SIZE,
|
||||
FlatBufferTabStateSerializer.getLaunchTypeFromFlatBuffer(
|
||||
@ -383,6 +388,10 @@ public class TabStateFileManagerUnitTest {
|
||||
TabLaunchTypeAtCreation.FROM_SYNC_BACKGROUND,
|
||||
FlatBufferTabStateSerializer.getLaunchTypeToFlatBuffer(
|
||||
TabLaunchType.FROM_SYNC_BACKGROUND));
|
||||
Assert.assertEquals(
|
||||
TabLaunchTypeAtCreation.FROM_RECENT_TABS_FOREGROUND,
|
||||
FlatBufferTabStateSerializer.getLaunchTypeToFlatBuffer(
|
||||
TabLaunchType.FROM_RECENT_TABS_FOREGROUND));
|
||||
Assert.assertEquals(
|
||||
TabLaunchTypeAtCreation.UNSET,
|
||||
FlatBufferTabStateSerializer.getLaunchTypeToFlatBuffer(TabLaunchType.UNSET));
|
||||
|
@ -42,6 +42,7 @@ enum TabLaunchTypeAtCreation:int {
|
||||
FROM_OMNIBOX = 21,
|
||||
UNSET = 22,
|
||||
FROM_SYNC_BACKGROUND = 23,
|
||||
FROM_RECENT_TABS_FOREGROUND = 24,
|
||||
// Add new values here and don't change existing values
|
||||
// as they are persisted across restarts. Changing existing
|
||||
// values will lead to backwards compatibility issues crbug.com/1286984.
|
||||
|
@ -143,7 +143,8 @@ std::string AndroidLiveTabContext::GetWorkspace() const {
|
||||
sessions::LiveTab* AndroidLiveTabContext::AddRestoredTab(
|
||||
const sessions::tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select) {
|
||||
bool select,
|
||||
sessions::tab_restore::Type original_session_type) {
|
||||
Profile* profile = tab_model_->GetProfile();
|
||||
|
||||
// Prepare navigation history.
|
||||
@ -165,8 +166,11 @@ sessions::LiveTab* AndroidLiveTabContext::AddRestoredTab(
|
||||
&nav_entries);
|
||||
|
||||
// Create new tab. Ownership is passed into java, which in turn creates a new
|
||||
// TabAndroid instance to own the WebContents.
|
||||
tab_model_->CreateTab(nullptr, web_contents.release());
|
||||
// TabAndroid instance to own the WebContents. Only select the restored tab
|
||||
// when restoring a single tab from a TAB session.
|
||||
tab_model_->CreateTab(
|
||||
nullptr, web_contents.release(),
|
||||
original_session_type == sessions::tab_restore::TAB ? true : false);
|
||||
// Don't load the tab yet. This prevents a renderer from starting which keeps
|
||||
// the tab restore lightweight as the tab is opened in the background only.
|
||||
// The tab will be in a "renderer was lost" state. This is recovered from when
|
||||
|
@ -61,9 +61,11 @@ class AndroidLiveTabContext : public sessions::LiveTabContext {
|
||||
const gfx::Rect GetRestoredBounds() const override;
|
||||
ui::WindowShowState GetRestoredState() const override;
|
||||
std::string GetWorkspace() const override;
|
||||
sessions::LiveTab* AddRestoredTab(const sessions::tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select) override;
|
||||
sessions::LiveTab* AddRestoredTab(
|
||||
const sessions::tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select,
|
||||
sessions::tab_restore::Type original_session_type) override;
|
||||
sessions::LiveTab* ReplaceRestoredTab(
|
||||
const sessions::tab_restore::Tab&) override;
|
||||
void CloseTab() override;
|
||||
|
@ -103,9 +103,11 @@ void AndroidLiveTabContextRestoreWrapper::SetVisualDataForGroup(
|
||||
sessions::LiveTab* AndroidLiveTabContextRestoreWrapper::AddRestoredTab(
|
||||
const sessions::tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select) {
|
||||
bool select,
|
||||
sessions::tab_restore::Type original_session_type) {
|
||||
auto* live_tab =
|
||||
AndroidLiveTabContext::AddRestoredTab(tab, tab_index, select);
|
||||
AndroidLiveTabContext::AddRestoredTab(tab, tab_index, select,
|
||||
original_session_type);
|
||||
if (tab.group) {
|
||||
TabAndroid* restored_tab = TabAndroid::FromWebContents(
|
||||
static_cast<sessions::ContentLiveTab*>(live_tab)->web_contents());
|
||||
|
@ -145,9 +145,11 @@ class AndroidLiveTabContextRestoreWrapper : public AndroidLiveTabContext {
|
||||
void SetVisualDataForGroup(
|
||||
const tab_groups::TabGroupId& group,
|
||||
const tab_groups::TabGroupVisualData& visual_data) override;
|
||||
sessions::LiveTab* AddRestoredTab(const sessions::tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select) override;
|
||||
sessions::LiveTab* AddRestoredTab(
|
||||
const sessions::tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select,
|
||||
sessions::tab_restore::Type original_session_type) override;
|
||||
|
||||
// Returns the TabGroup data aggregated via AddRestoredTab.
|
||||
const std::map<tab_groups::TabGroupId, TabGroup>& GetTabGroups();
|
||||
|
@ -119,6 +119,9 @@ class TabModel {
|
||||
UNSET,
|
||||
// Used when creating a tab to keep synced tab groups up to date.
|
||||
FROM_SYNC_BACKGROUND,
|
||||
// Open most recent tab in foregroud, used by ctrl-shift-t to restore
|
||||
// most recently closed tab or tabs.
|
||||
FROM_RECENT_TABS_FOREGROUND,
|
||||
// Must be last.
|
||||
SIZE
|
||||
};
|
||||
@ -184,7 +187,8 @@ class TabModel {
|
||||
|
||||
// Used for restoring tabs from synced foreign sessions.
|
||||
virtual void CreateTab(TabAndroid* parent,
|
||||
content::WebContents* web_contents) = 0;
|
||||
content::WebContents* web_contents,
|
||||
bool select) = 0;
|
||||
|
||||
virtual void HandlePopupNavigation(TabAndroid* parent,
|
||||
NavigateParams* params) = 0;
|
||||
|
@ -78,14 +78,15 @@ int TabModelJniBridge::GetActiveIndex() const {
|
||||
}
|
||||
|
||||
void TabModelJniBridge::CreateTab(TabAndroid* parent,
|
||||
WebContents* web_contents) {
|
||||
WebContents* web_contents,
|
||||
bool select) {
|
||||
JNIEnv* env = AttachCurrentThread();
|
||||
Profile* profile =
|
||||
Profile::FromBrowserContext(web_contents->GetBrowserContext());
|
||||
|
||||
Java_TabModelJniBridge_createTabWithWebContents(
|
||||
env, java_object_.get(env), (parent ? parent->GetJavaObject() : nullptr),
|
||||
profile->GetJavaObject(), web_contents->GetJavaWebContents());
|
||||
profile->GetJavaObject(), web_contents->GetJavaWebContents(), select);
|
||||
}
|
||||
|
||||
void TabModelJniBridge::HandlePopupNavigation(TabAndroid* parent,
|
||||
|
@ -53,7 +53,8 @@ class TabModelJniBridge : public TabModel {
|
||||
void CloseTabAt(int index) override;
|
||||
|
||||
void CreateTab(TabAndroid* parent,
|
||||
content::WebContents* web_contents) override;
|
||||
content::WebContents* web_contents,
|
||||
bool select) override;
|
||||
void HandlePopupNavigation(TabAndroid* parent,
|
||||
NavigateParams* params) override;
|
||||
|
||||
|
@ -34,7 +34,8 @@ base::android::ScopedJavaLocalRef<jobject> TestTabModel::GetJavaObject() const {
|
||||
}
|
||||
|
||||
void TestTabModel::CreateTab(TabAndroid* parent,
|
||||
content::WebContents* web_contents) {}
|
||||
content::WebContents* web_contents,
|
||||
bool select) {}
|
||||
|
||||
void TestTabModel::HandlePopupNavigation(TabAndroid* parent,
|
||||
NavigateParams* params) {}
|
||||
|
@ -21,7 +21,8 @@ class TestTabModel : public TabModel {
|
||||
content::WebContents* GetWebContentsAt(int index) const override;
|
||||
base::android::ScopedJavaLocalRef<jobject> GetJavaObject() const override;
|
||||
void CreateTab(TabAndroid* parent,
|
||||
content::WebContents* web_contents) override;
|
||||
content::WebContents* web_contents,
|
||||
bool select) override;
|
||||
void HandlePopupNavigation(TabAndroid* parent,
|
||||
NavigateParams* params) override;
|
||||
content::WebContents* CreateNewTabForDevTools(const GURL& url) override;
|
||||
|
@ -206,7 +206,8 @@ std::string BrowserLiveTabContext::GetWorkspace() const {
|
||||
sessions::LiveTab* BrowserLiveTabContext::AddRestoredTab(
|
||||
const sessions::tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select) {
|
||||
bool select,
|
||||
sessions::tab_restore::Type original_session_type) {
|
||||
tab_groups::SavedTabGroupKeyedService* saved_tab_group_service =
|
||||
tab_groups::SavedTabGroupServiceFactory::GetForProfile(
|
||||
browser_->profile());
|
||||
|
@ -68,9 +68,11 @@ class BrowserLiveTabContext : public sessions::LiveTabContext {
|
||||
const gfx::Rect GetRestoredBounds() const override;
|
||||
ui::WindowShowState GetRestoredState() const override;
|
||||
std::string GetWorkspace() const override;
|
||||
sessions::LiveTab* AddRestoredTab(const sessions::tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select) override;
|
||||
sessions::LiveTab* AddRestoredTab(
|
||||
const sessions::tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select,
|
||||
sessions::tab_restore::Type original_session_type) override;
|
||||
sessions::LiveTab* ReplaceRestoredTab(
|
||||
const sessions::tab_restore::Tab& tab) override;
|
||||
void CloseTab() override;
|
||||
|
@ -72,9 +72,12 @@ class SESSIONS_EXPORT LiveTabContext {
|
||||
// platform-specific data).
|
||||
// |tab.id| is the tab's unique SessionID. Only present if a historical tab
|
||||
// has been created by TabRestoreService.
|
||||
// |original_session_type| indicates the type of session entry the tab
|
||||
// belongs to.
|
||||
virtual LiveTab* AddRestoredTab(const tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select) = 0;
|
||||
bool select,
|
||||
tab_restore::Type original_session_type) = 0;
|
||||
|
||||
// Note: |tab.platform_data| may be null (e.g., if restoring from last session
|
||||
// as this data is not persisted, or if the platform does not provide
|
||||
|
@ -471,7 +471,8 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTabOrGroupFromWindow(
|
||||
// Restore the tab.
|
||||
restored_tab_browser_id = tab.browser_id;
|
||||
LiveTab* restored_tab = nullptr;
|
||||
context = RestoreTab(tab, context, disposition, &restored_tab);
|
||||
context = RestoreTab(tab, context, disposition,
|
||||
sessions::tab_restore::WINDOW, &restored_tab);
|
||||
live_tabs->push_back(restored_tab);
|
||||
|
||||
std::optional<tab_groups::TabGroupId> group_id = tab.group;
|
||||
@ -521,7 +522,8 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTabOrGroupFromWindow(
|
||||
// Restore the tab.
|
||||
LiveTab* restored_tab = nullptr;
|
||||
LiveTabContext* new_context =
|
||||
RestoreTab(tab, context, disposition, &restored_tab);
|
||||
RestoreTab(tab, context, disposition, sessions::tab_restore::WINDOW,
|
||||
&restored_tab);
|
||||
if (tab_i != 0) {
|
||||
// CHECK that the context should be the same except for the first tab.
|
||||
DCHECK_EQ(new_context, context);
|
||||
@ -596,7 +598,8 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreEntryById(
|
||||
}
|
||||
|
||||
LiveTab* restored_tab = nullptr;
|
||||
context = RestoreTab(tab, context, disposition, &restored_tab);
|
||||
context =
|
||||
RestoreTab(tab, context, disposition, entry.type, &restored_tab);
|
||||
live_tabs.push_back(restored_tab);
|
||||
context->ShowBrowserWindow();
|
||||
break;
|
||||
@ -634,7 +637,7 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreEntryById(
|
||||
for (const auto& tab : window.tabs) {
|
||||
const bool select_tab = tab->id == selected_tab_id;
|
||||
LiveTab* restored_tab = context->AddRestoredTab(
|
||||
*tab.get(), context->GetTabCount(), select_tab);
|
||||
*tab.get(), context->GetTabCount(), select_tab, entry.type);
|
||||
|
||||
if (restored_tab) {
|
||||
client_->OnTabRestored(
|
||||
@ -684,7 +687,8 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreEntryById(
|
||||
if (entry_id_matches_restore_id) {
|
||||
for (const auto& tab : group.tabs) {
|
||||
LiveTab* restored_tab = context->AddRestoredTab(
|
||||
*tab.get(), context->GetTabCount(), group.tabs[0]->id == tab->id);
|
||||
*tab.get(), context->GetTabCount(), group.tabs[0]->id == tab->id,
|
||||
entry.type);
|
||||
live_tabs.push_back(restored_tab);
|
||||
}
|
||||
} else {
|
||||
@ -694,7 +698,8 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreEntryById(
|
||||
const Tab& tab = *group.tabs[i];
|
||||
if (tab.id == id) {
|
||||
LiveTab* restored_tab = nullptr;
|
||||
context = RestoreTab(tab, context, disposition, &restored_tab);
|
||||
context = RestoreTab(tab, context, disposition, entry.type,
|
||||
&restored_tab);
|
||||
live_tabs.push_back(restored_tab);
|
||||
CHECK(ValidateGroup(group));
|
||||
group.tabs.erase(group.tabs.begin() + i);
|
||||
@ -940,6 +945,7 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTab(
|
||||
const Tab& tab,
|
||||
LiveTabContext* context,
|
||||
WindowOpenDisposition disposition,
|
||||
sessions::tab_restore::Type session_restore_type,
|
||||
LiveTab** live_tab) {
|
||||
LiveTab* restored_tab;
|
||||
if (disposition == WindowOpenDisposition::CURRENT_TAB && context) {
|
||||
@ -989,7 +995,8 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTab(
|
||||
|
||||
restored_tab = context->AddRestoredTab(
|
||||
tab, tab_index,
|
||||
/*select=*/disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB);
|
||||
/*select=*/disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB,
|
||||
session_restore_type);
|
||||
}
|
||||
|
||||
client_->OnTabRestored(
|
||||
|
@ -154,9 +154,12 @@ class SESSIONS_EXPORT TabRestoreServiceHelper
|
||||
// will be respected instead. If a new LiveTabContext needs to be created for
|
||||
// this tab, If present, |live_tab| will be populated with the LiveTab of the
|
||||
// restored tab.
|
||||
// |original_session_type| indicates the type of session entry the tab
|
||||
// belongs to.
|
||||
LiveTabContext* RestoreTab(const Tab& tab,
|
||||
LiveTabContext* context,
|
||||
WindowOpenDisposition disposition,
|
||||
sessions::tab_restore::Type session_restore_type,
|
||||
LiveTab** live_tab);
|
||||
|
||||
// This is a helper function for RestoreEntryById(). Restores a single entry
|
||||
|
@ -61,9 +61,11 @@ class LiveTabContextBrowserAgent
|
||||
const gfx::Rect GetRestoredBounds() const override;
|
||||
ui::WindowShowState GetRestoredState() const override;
|
||||
std::string GetWorkspace() const override;
|
||||
sessions::LiveTab* AddRestoredTab(const sessions::tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select) override;
|
||||
sessions::LiveTab* AddRestoredTab(
|
||||
const sessions::tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select,
|
||||
sessions::tab_restore::Type original_session_type) override;
|
||||
sessions::LiveTab* ReplaceRestoredTab(
|
||||
const sessions::tab_restore::Tab& tab) override;
|
||||
void CloseTab() override;
|
||||
|
@ -130,7 +130,8 @@ std::string LiveTabContextBrowserAgent::GetWorkspace() const {
|
||||
sessions::LiveTab* LiveTabContextBrowserAgent::AddRestoredTab(
|
||||
const sessions::tab_restore::Tab& tab,
|
||||
int tab_index,
|
||||
bool select) {
|
||||
bool select,
|
||||
sessions::tab_restore::Type original_session_type) {
|
||||
// TODO(crbug.com/40491734): Handle tab-switch animation somehow...
|
||||
web_state_list_->InsertWebState(
|
||||
session_util::CreateWebStateWithNavigationEntries(
|
||||
|
@ -4513,6 +4513,8 @@ chromium-metrics-reviews@google.com.
|
||||
<variant name="ReadingList" summary="tabs opened from the reading list"/>
|
||||
<variant name="RecentTabs"
|
||||
summary="tabs opened in backrgound from recent tabs"/>
|
||||
<variant name="RecentTabsForeground"
|
||||
summary="tabs opened in foreground from recent tabs"/>
|
||||
<variant name="Reparenting" summary="tabs opened from changing windows"/>
|
||||
<variant name="Restore" summary="tabs opened from restores"/>
|
||||
<variant name="SpeculativeBackgroundCreation"
|
||||
|
Reference in New Issue
Block a user