Commit b2e0cf11 authored by Scott Violet's avatar Scott Violet Committed by Commit Bot

weblayer: adds a persistent id for tabs

This way the embedder has a way to persist state with a tab.
Without this the embedder has no way to identify what tab the data
was associated with.

BUG=1056710
TEST=BrowserFragmentLifecycleTests

Change-Id: I944e538ba0110f5d3434d5dfd8aa76fe2fdd08e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2093691
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarEvan Stade <estade@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748314}
parent e6157156
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <vector> #include <vector>
#include "base/containers/flat_set.h" #include "base/containers/flat_set.h"
#include "base/guid.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/pickle.h" #include "base/pickle.h"
#include "base/token.h" #include "base/token.h"
...@@ -64,6 +65,7 @@ static const SessionCommand::id_type kCommandTabNavigationPathPruned = 24; ...@@ -64,6 +65,7 @@ static const SessionCommand::id_type kCommandTabNavigationPathPruned = 24;
static const SessionCommand::id_type kCommandSetTabGroup = 25; static const SessionCommand::id_type kCommandSetTabGroup = 25;
static const SessionCommand::id_type kCommandSetTabGroupMetadata = 26; static const SessionCommand::id_type kCommandSetTabGroupMetadata = 26;
static const SessionCommand::id_type kCommandSetTabGroupMetadata2 = 27; static const SessionCommand::id_type kCommandSetTabGroupMetadata2 = 27;
static const SessionCommand::id_type kCommandSetTabGuid = 28;
namespace { namespace {
...@@ -778,9 +780,21 @@ bool CreateTabsAndWindows( ...@@ -778,9 +780,21 @@ bool CreateTabsAndWindows(
break; break;
} }
case kCommandSetTabGuid: {
std::unique_ptr<base::Pickle> pickle(command->PayloadAsPickle());
base::PickleIterator it(*pickle);
SessionID::id_type tab_id = -1;
std::string guid;
if (!it.ReadInt(&tab_id) || !it.ReadString(&guid) ||
!base::IsValidGUID(guid)) {
DVLOG(1) << "Failed reading command " << command->id();
return true;
}
GetTab(SessionID::FromSerializedValue(tab_id), tabs)->guid = guid;
break;
}
default: default:
// TODO(skuhne): This might call back into a callback handler to extend
// the command set for specific implementations.
DVLOG(1) << "Failed reading an unknown command " << command->id(); DVLOG(1) << "Failed reading an unknown command " << command->id();
return true; return true;
} }
...@@ -986,6 +1000,15 @@ std::unique_ptr<SessionCommand> CreateSetWindowAppNameCommand( ...@@ -986,6 +1000,15 @@ std::unique_ptr<SessionCommand> CreateSetWindowAppNameCommand(
app_name); app_name);
} }
std::unique_ptr<SessionCommand> CreateSetTabGuidCommand(
const SessionID& tab_id,
const std::string& guid) {
base::Pickle pickle;
pickle.WriteInt(tab_id.id());
pickle.WriteString(guid);
return std::make_unique<SessionCommand>(kCommandSetTabGuid, pickle);
}
bool ReplacePendingCommand(CommandStorageManager* command_storage_manager, bool ReplacePendingCommand(CommandStorageManager* command_storage_manager,
std::unique_ptr<SessionCommand>* command) { std::unique_ptr<SessionCommand>* command) {
// We optimize page navigations, which can happen quite frequently and // We optimize page navigations, which can happen quite frequently and
......
...@@ -27,7 +27,6 @@ class SessionCommand; ...@@ -27,7 +27,6 @@ class SessionCommand;
// The following functions create sequentialized change commands which are // The following functions create sequentialized change commands which are
// used to reconstruct the current/previous session state. // used to reconstruct the current/previous session state.
// It is up to the caller to delete the returned SessionCommand* object.
SESSIONS_EXPORT std::unique_ptr<SessionCommand> SESSIONS_EXPORT std::unique_ptr<SessionCommand>
CreateSetSelectedTabInWindowCommand(const SessionID& window_id, int index); CreateSetSelectedTabInWindowCommand(const SessionID& window_id, int index);
SESSIONS_EXPORT std::unique_ptr<SessionCommand> CreateSetTabWindowCommand( SESSIONS_EXPORT std::unique_ptr<SessionCommand> CreateSetTabWindowCommand(
...@@ -89,6 +88,10 @@ SESSIONS_EXPORT std::unique_ptr<SessionCommand> CreateSetWindowWorkspaceCommand( ...@@ -89,6 +88,10 @@ SESSIONS_EXPORT std::unique_ptr<SessionCommand> CreateSetWindowWorkspaceCommand(
const SessionID& window_id, const SessionID& window_id,
const std::string& workspace); const std::string& workspace);
SESSIONS_EXPORT std::unique_ptr<SessionCommand> CreateSetTabGuidCommand(
const SessionID& tab_id,
const std::string& guid);
// Searches for a pending command using |command_storage_manager| that can be // Searches for a pending command using |command_storage_manager| that can be
// replaced with |command|. If one is found, pending command is removed, the // replaced with |command|. If one is found, pending command is removed, the
// command is added to the pending commands (taken ownership) and true is // command is added to the pending commands (taken ownership) and true is
......
...@@ -97,6 +97,9 @@ struct SESSIONS_EXPORT SessionTab { ...@@ -97,6 +97,9 @@ struct SESSIONS_EXPORT SessionTab {
// For reassociating sessionStorage. // For reassociating sessionStorage.
std::string session_storage_persistent_id; std::string session_storage_persistent_id;
// guid associated with the tab, may be empty.
std::string guid;
private: private:
DISALLOW_COPY_AND_ASSIGN(SessionTab); DISALLOW_COPY_AND_ASSIGN(SessionTab);
}; };
......
...@@ -37,7 +37,6 @@ public class BrowserFragmentLifecycleTest { ...@@ -37,7 +37,6 @@ public class BrowserFragmentLifecycleTest {
public void successfullyLoadsUrlAfterRecreation() { public void successfullyLoadsUrlAfterRecreation() {
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl("about:blank"); InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl("about:blank");
Tab tab = TestThreadUtils.runOnUiThreadBlockingNoException(() -> activity.getTab()); Tab tab = TestThreadUtils.runOnUiThreadBlockingNoException(() -> activity.getTab());
String url = "data:text,foo"; String url = "data:text,foo";
mActivityTestRule.navigateAndWait(tab, url, false); mActivityTestRule.navigateAndWait(tab, url, false);
...@@ -51,37 +50,19 @@ public class BrowserFragmentLifecycleTest { ...@@ -51,37 +50,19 @@ public class BrowserFragmentLifecycleTest {
@Test @Test
@SmallTest @SmallTest
public void restoreAfterRecreate() { public void restoreAfterRecreate() throws Throwable {
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl("about:blank"); InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl("about:blank");
Tab tab = TestThreadUtils.runOnUiThreadBlockingNoException(() -> activity.getTab()); Tab tab = TestThreadUtils.runOnUiThreadBlockingNoException(() -> activity.getTab());
String url = "data:text,foo"; String url = "data:text,foo";
mActivityTestRule.navigateAndWait(tab, url, false); mActivityTestRule.navigateAndWait(tab, url, false);
mActivityTestRule.recreateActivity(); mActivityTestRule.recreateActivity();
InstrumentationActivity newActivity = mActivityTestRule.getActivity(); InstrumentationActivity newActivity = mActivityTestRule.getActivity();
BoundedCountDownLatch latch = new BoundedCountDownLatch(1); waitForTabToFinishRestore(TestThreadUtils.runOnUiThreadBlocking(() -> {
TestThreadUtils.runOnUiThreadBlocking(() -> { return mActivityTestRule.getActivity().getTab();
Tab restoredTab = newActivity.getTab(); }),
// It's possible the NavigationController hasn't loaded yet, handle either scenario. url);
NavigationController navigationController = restoredTab.getNavigationController();
if (navigationController.getNavigationListSize() == 1
&& navigationController.getNavigationEntryDisplayUri(0).equals(
Uri.parse(url))) {
latch.countDown();
return;
}
navigationController.registerNavigationCallback(new NavigationCallback() {
@Override
public void onNavigationCompleted(@NonNull Navigation navigation) {
if (navigation.getUri().equals(Uri.parse(url))) {
latch.countDown();
}
}
});
});
latch.timedAwait();
} }
// https://crbug.com/1021041 // https://crbug.com/1021041
...@@ -107,16 +88,8 @@ public class BrowserFragmentLifecycleTest { ...@@ -107,16 +88,8 @@ public class BrowserFragmentLifecycleTest {
latch.timedAwait(); latch.timedAwait();
} }
private void restoresPreviousSession(Bundle extras) { // Waits for |tab| to finish loadding |url. This is intended to be called after restore.
extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, "x"); private void waitForTabToFinishRestore(Tab tab, String url) {
final String url = mActivityTestRule.getTestDataURL("simple_page.html");
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(url, extras);
mActivityTestRule.recreateActivity();
InstrumentationActivity newActivity = mActivityTestRule.getActivity();
Tab tab = TestThreadUtils.runOnUiThreadBlockingNoException(() -> newActivity.getTab());
Assert.assertNotNull(tab);
BoundedCountDownLatch latch = new BoundedCountDownLatch(1); BoundedCountDownLatch latch = new BoundedCountDownLatch(1);
TestThreadUtils.runOnUiThreadBlocking(() -> { TestThreadUtils.runOnUiThreadBlocking(() -> {
// It's possible the NavigationController hasn't loaded yet, handle either scenario. // It's possible the NavigationController hasn't loaded yet, handle either scenario.
...@@ -139,18 +112,77 @@ public class BrowserFragmentLifecycleTest { ...@@ -139,18 +112,77 @@ public class BrowserFragmentLifecycleTest {
latch.timedAwait(); latch.timedAwait();
} }
// Recreates the activity and waits for the first tab to be restored. |extras| is the Bundle
// used to launch the shell.
private void restoresPreviousSession(Bundle extras) {
extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, "x");
final String url = mActivityTestRule.getTestDataURL("simple_page.html");
mActivityTestRule.launchShellWithUrl(url, extras);
mActivityTestRule.recreateActivity();
InstrumentationActivity newActivity = mActivityTestRule.getActivity();
Assert.assertNotNull(newActivity);
Tab tab = TestThreadUtils.runOnUiThreadBlockingNoException(() -> newActivity.getTab());
Assert.assertNotNull(tab);
waitForTabToFinishRestore(tab, url);
}
@Test @Test
@SmallTest @SmallTest
public void restoresPreviousSession() throws InterruptedException { public void restoresPreviousSession() throws Throwable {
restoresPreviousSession(new Bundle()); restoresPreviousSession(new Bundle());
} }
@Test @Test
@SmallTest @SmallTest
public void restoresPreviousSessionIncognito() throws InterruptedException { public void restoresPreviousSessionIncognito() throws Throwable {
Bundle extras = new Bundle(); Bundle extras = new Bundle();
// This forces incognito. // This forces incognito.
extras.putString(InstrumentationActivity.EXTRA_PROFILE_NAME, null); extras.putString(InstrumentationActivity.EXTRA_PROFILE_NAME, null);
restoresPreviousSession(extras); restoresPreviousSession(extras);
} }
@Test
@SmallTest
public void restoresTabGuid() throws Throwable {
Bundle extras = new Bundle();
extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, "x");
final String url = mActivityTestRule.getTestDataURL("simple_page.html");
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(url, extras);
final String initialTabId = TestThreadUtils.runOnUiThreadBlocking(
() -> { return mActivityTestRule.getActivity().getTab().getGuid(); });
Assert.assertNotNull(initialTabId);
Assert.assertFalse(initialTabId.isEmpty());
mActivityTestRule.recreateActivity();
InstrumentationActivity newActivity = mActivityTestRule.getActivity();
Tab tab = TestThreadUtils.runOnUiThreadBlockingNoException(() -> newActivity.getTab());
Assert.assertNotNull(tab);
waitForTabToFinishRestore(tab, url);
final String restoredTabId =
TestThreadUtils.runOnUiThreadBlockingNoException(() -> { return tab.getGuid(); });
Assert.assertEquals(initialTabId, restoredTabId);
}
@Test
@SmallTest
public void restoreTabGuidAfterRecreate() throws Throwable {
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl("about:blank");
final Tab tab = TestThreadUtils.runOnUiThreadBlockingNoException(() -> activity.getTab());
final String initialTabId = TestThreadUtils.runOnUiThreadBlocking(
() -> { return mActivityTestRule.getActivity().getTab().getGuid(); });
String url = "data:text,foo";
mActivityTestRule.navigateAndWait(tab, url, false);
mActivityTestRule.recreateActivity();
InstrumentationActivity newActivity = mActivityTestRule.getActivity();
final Tab restoredTab =
TestThreadUtils.runOnUiThreadBlockingNoException(() -> newActivity.getTab());
waitForTabToFinishRestore(restoredTab, url);
final String restoredTabId = TestThreadUtils.runOnUiThreadBlockingNoException(
() -> { return restoredTab.getGuid(); });
Assert.assertEquals(initialTabId, restoredTabId);
}
} }
...@@ -59,9 +59,10 @@ BrowserImpl::~BrowserImpl() { ...@@ -59,9 +59,10 @@ BrowserImpl::~BrowserImpl() {
} }
TabImpl* BrowserImpl::CreateTabForSessionRestore( TabImpl* BrowserImpl::CreateTabForSessionRestore(
std::unique_ptr<content::WebContents> web_contents) { std::unique_ptr<content::WebContents> web_contents,
const std::string& guid) {
std::unique_ptr<TabImpl> tab = std::unique_ptr<TabImpl> tab =
std::make_unique<TabImpl>(profile_, std::move(web_contents)); std::make_unique<TabImpl>(profile_, std::move(web_contents), guid);
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
Java_BrowserImpl_createTabForSessionRestore( Java_BrowserImpl_createTabForSessionRestore(
AttachCurrentThread(), java_impl_, reinterpret_cast<jlong>(tab.get())); AttachCurrentThread(), java_impl_, reinterpret_cast<jlong>(tab.get()));
......
...@@ -43,7 +43,8 @@ class BrowserImpl : public Browser { ...@@ -43,7 +43,8 @@ class BrowserImpl : public Browser {
// Creates and adds a Tab from session restore. The returned tab is owned by // Creates and adds a Tab from session restore. The returned tab is owned by
// this Browser. // this Browser.
TabImpl* CreateTabForSessionRestore( TabImpl* CreateTabForSessionRestore(
std::unique_ptr<content::WebContents> web_contents); std::unique_ptr<content::WebContents> web_contents,
const std::string& guid);
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
void AddTab(JNIEnv* env, void AddTab(JNIEnv* env,
......
...@@ -433,6 +433,11 @@ public final class TabImpl extends ITab.Stub { ...@@ -433,6 +433,11 @@ public final class TabImpl extends ITab.Stub {
return false; return false;
} }
@Override
public String getGuid() {
return TabImplJni.get().getGuid(mNativeTab);
}
@CalledByNative @CalledByNative
private static RectF createRectF(float x, float y, float right, float bottom) { private static RectF createRectF(float x, float y, float right, float bottom) {
return new RectF(x, y, right, bottom); return new RectF(x, y, right, bottom);
...@@ -575,5 +580,6 @@ public final class TabImpl extends ITab.Stub { ...@@ -575,5 +580,6 @@ public final class TabImpl extends ITab.Stub {
void executeScript(long nativeTabImpl, String script, boolean useSeparateIsolate, void executeScript(long nativeTabImpl, String script, boolean useSeparateIsolate,
Callback<String> callback); Callback<String> callback);
void updateBrowserControlsState(long nativeTabImpl, int newConstraint); void updateBrowserControlsState(long nativeTabImpl, int newConstraint);
String getGuid(long nativeTabImpl);
} }
} }
...@@ -38,5 +38,8 @@ interface ITab { ...@@ -38,5 +38,8 @@ interface ITab {
void dismissTabModalOverlay() = 10; void dismissTabModalOverlay() = 10;
void dispatchBeforeUnloadAndClose() = 11; void dispatchBeforeUnloadAndClose() = 11;
boolean dismissTransientUi() = 12; boolean dismissTransientUi() = 12;
String getGuid() = 13;
} }
...@@ -76,7 +76,8 @@ void ProcessRestoreCommands( ...@@ -76,7 +76,8 @@ void ProcessRestoreCommands(
content::RestoreType::CURRENT_SESSION, content::RestoreType::CURRENT_SESSION,
&entries); &entries);
DCHECK(entries.empty()); DCHECK(entries.empty());
TabImpl* tab = browser->CreateTabForSessionRestore(std::move(web_contents)); TabImpl* tab = browser->CreateTabForSessionRestore(std::move(web_contents),
session_tab.guid);
if (!had_tabs && i == (windows[0])->selected_tab_index) if (!had_tabs && i == (windows[0])->selected_tab_index)
browser->SetActiveTab(tab); browser->SetActiveTab(tab);
...@@ -97,7 +98,8 @@ void RestoreBrowserState( ...@@ -97,7 +98,8 @@ void RestoreBrowserState(
if (browser->GetTabs().empty()) { if (browser->GetTabs().empty()) {
// Nothing to restore, or restore failed. Create a default tab. // Nothing to restore, or restore failed. Create a default tab.
browser->SetActiveTab(browser->CreateTabForSessionRestore(nullptr)); browser->SetActiveTab(
browser->CreateTabForSessionRestore(nullptr, std::string()));
} }
} }
...@@ -107,25 +109,27 @@ BuildCommandsForTabConfiguration(const SessionID& browser_session_id, ...@@ -107,25 +109,27 @@ BuildCommandsForTabConfiguration(const SessionID& browser_session_id,
int index_in_browser) { int index_in_browser) {
DCHECK(tab); DCHECK(tab);
std::vector<std::unique_ptr<sessions::SessionCommand>> result; std::vector<std::unique_ptr<sessions::SessionCommand>> result;
const SessionID& session_id = GetSessionIDForTab(tab); const SessionID& tab_id = GetSessionIDForTab(tab);
result.push_back( result.push_back(
sessions::CreateSetTabWindowCommand(browser_session_id, session_id)); sessions::CreateSetTabWindowCommand(browser_session_id, tab_id));
result.push_back(sessions::CreateLastActiveTimeCommand( result.push_back(sessions::CreateLastActiveTimeCommand(
session_id, tab->web_contents()->GetLastActiveTime())); tab_id, tab->web_contents()->GetLastActiveTime()));
const std::string& ua_override = tab->web_contents()->GetUserAgentOverride(); const std::string& ua_override = tab->web_contents()->GetUserAgentOverride();
if (!ua_override.empty()) { if (!ua_override.empty()) {
result.push_back(sessions::CreateSetTabUserAgentOverrideCommand( result.push_back(
session_id, ua_override)); sessions::CreateSetTabUserAgentOverrideCommand(tab_id, ua_override));
} }
if (index_in_browser != -1) { if (index_in_browser != -1) {
result.push_back(sessions::CreateSetTabIndexInWindowCommand( result.push_back(
session_id, index_in_browser)); sessions::CreateSetTabIndexInWindowCommand(tab_id, index_in_browser));
} }
result.push_back(sessions::CreateSetSelectedNavigationIndexCommand( result.push_back(sessions::CreateSetSelectedNavigationIndexCommand(
session_id, tab->web_contents()->GetController().GetCurrentEntryIndex())); tab_id, tab->web_contents()->GetController().GetCurrentEntryIndex()));
result.push_back(sessions::CreateSetTabGuidCommand(tab_id, tab->GetGuid()));
return result; return result;
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/guid.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "build/build_config.h" #include "build/build_config.h"
...@@ -203,6 +204,32 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, SingleTab) { ...@@ -203,6 +204,32 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, SingleTab) {
->GetNavigationListSize()); ->GetNavigationListSize());
} }
IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, RestoresGuid) {
ASSERT_TRUE(embedded_test_server()->Start());
std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x");
Tab* tab = browser->AddTab(Tab::Create(GetProfile()));
const std::string original_guid = tab->GetGuid();
EXPECT_FALSE(original_guid.empty());
EXPECT_TRUE(base::IsValidGUID(original_guid));
const GURL url = embedded_test_server()->GetURL("/simple_page.html");
NavigateAndWaitForCompletion(url, tab);
ShutdownBrowserPersisterAndWait(browser.get());
tab = nullptr;
browser.reset();
browser = CreateBrowser(GetProfile(), "x");
// Should be no tabs while waiting for restore.
EXPECT_TRUE(browser->GetTabs().empty());
// Wait for the restore and navigation to complete.
BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
browser.get(), url);
ASSERT_EQ(1u, browser->GetTabs().size());
EXPECT_EQ(browser->GetTabs()[0], browser->GetActiveTab());
EXPECT_EQ(original_guid, browser->GetTabs()[0]->GetGuid());
}
IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, TwoTabs) { IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, TwoTabs) {
ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(embedded_test_server()->Start());
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/auto_reset.h" #include "base/auto_reset.h"
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/guid.h"
#include "base/logging.h" #include "base/logging.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/autofill_manager.h"
...@@ -159,8 +160,11 @@ TabImpl::TabImpl(ProfileImpl* profile, const JavaParamRef<jobject>& java_impl) ...@@ -159,8 +160,11 @@ TabImpl::TabImpl(ProfileImpl* profile, const JavaParamRef<jobject>& java_impl)
#endif #endif
TabImpl::TabImpl(ProfileImpl* profile, TabImpl::TabImpl(ProfileImpl* profile,
std::unique_ptr<content::WebContents> web_contents) std::unique_ptr<content::WebContents> web_contents,
: profile_(profile), web_contents_(std::move(web_contents)) { const std::string& guid)
: profile_(profile),
web_contents_(std::move(web_contents)),
guid_(guid.empty() ? base::GenerateGUID() : guid) {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
g_last_tab = this; g_last_tab = this;
#endif #endif
...@@ -291,6 +295,10 @@ void TabImpl::ExecuteScript(const base::string16& script, ...@@ -291,6 +295,10 @@ void TabImpl::ExecuteScript(const base::string16& script,
} }
} }
const std::string& TabImpl::GetGuid() {
return guid_;
}
void TabImpl::ExecuteScriptWithUserGestureForTests( void TabImpl::ExecuteScriptWithUserGestureForTests(
const base::string16& script) { const base::string16& script) {
web_contents_->GetMainFrame()->ExecuteJavaScriptWithUserGestureForTests( web_contents_->GetMainFrame()->ExecuteJavaScriptWithUserGestureForTests(
...@@ -416,6 +424,11 @@ void TabImpl::UpdateBrowserControlsState(JNIEnv* env, jint constraint) { ...@@ -416,6 +424,11 @@ void TabImpl::UpdateBrowserControlsState(JNIEnv* env, jint constraint) {
->UpdateBrowserControlsState(state_constraint, current_state, animate); ->UpdateBrowserControlsState(state_constraint, current_state, animate);
} }
} }
ScopedJavaLocalRef<jstring> TabImpl::GetGuid(JNIEnv* env) {
return base::android::ConvertUTF8ToJavaString(AttachCurrentThread(),
GetGuid());
}
#endif #endif
content::WebContents* TabImpl::OpenURLFromTab( content::WebContents* TabImpl::OpenURLFromTab(
......
...@@ -60,7 +60,8 @@ class TabImpl : public Tab, ...@@ -60,7 +60,8 @@ class TabImpl : public Tab,
const base::android::JavaParamRef<jobject>& java_impl); const base::android::JavaParamRef<jobject>& java_impl);
#endif #endif
explicit TabImpl(ProfileImpl* profile, explicit TabImpl(ProfileImpl* profile,
std::unique_ptr<content::WebContents> = nullptr); std::unique_ptr<content::WebContents> = nullptr,
const std::string& guid = std::string());
~TabImpl() override; ~TabImpl() override;
// Returns the TabImpl from the specified WebContents, or null if // Returns the TabImpl from the specified WebContents, or null if
...@@ -116,6 +117,8 @@ class TabImpl : public Tab, ...@@ -116,6 +117,8 @@ class TabImpl : public Tab,
const base::android::JavaParamRef<jobject>& autofill_provider); const base::android::JavaParamRef<jobject>& autofill_provider);
void UpdateBrowserControlsState(JNIEnv* env, jint constraint); void UpdateBrowserControlsState(JNIEnv* env, jint constraint);
base::android::ScopedJavaLocalRef<jstring> GetGuid(JNIEnv* env);
#endif #endif
DownloadDelegate* download_delegate() { return download_delegate_; } DownloadDelegate* download_delegate() { return download_delegate_; }
...@@ -133,6 +136,7 @@ class TabImpl : public Tab, ...@@ -133,6 +136,7 @@ class TabImpl : public Tab,
void ExecuteScript(const base::string16& script, void ExecuteScript(const base::string16& script,
bool use_separate_isolate, bool use_separate_isolate,
JavaScriptResultCallback callback) override; JavaScriptResultCallback callback) override;
const std::string& GetGuid() override;
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
void AttachToView(views::WebView* web_view) override; void AttachToView(views::WebView* web_view) override;
#endif #endif
...@@ -243,6 +247,8 @@ class TabImpl : public Tab, ...@@ -243,6 +247,8 @@ class TabImpl : public Tab,
std::unique_ptr<autofill::AutofillProvider> autofill_provider_; std::unique_ptr<autofill::AutofillProvider> autofill_provider_;
const std::string guid_;
base::WeakPtrFactory<TabImpl> weak_ptr_factory_{this}; base::WeakPtrFactory<TabImpl> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(TabImpl); DISALLOW_COPY_AND_ASSIGN(TabImpl);
......
...@@ -308,6 +308,24 @@ public class Tab { ...@@ -308,6 +308,24 @@ public class Tab {
return mImpl; return mImpl;
} }
/**
* Returns a unique id that persists across restarts.
*
* @return the unique id.
* @since 82
*/
public String getGuid() {
ThreadCheck.ensureOnUiThread();
if (WebLayer.getSupportedMajorVersionInternal() < 82) {
throw new UnsupportedOperationException();
}
try {
return mImpl.getGuid();
} catch (RemoteException e) {
throw new APICallException(e);
}
}
private final class TabClientImpl extends ITabClient.Stub { private final class TabClientImpl extends ITabClient.Stub {
@Override @Override
public void visibleUriChanged(String uriString) { public void visibleUriChanged(String uriString) {
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define WEBLAYER_PUBLIC_TAB_H_ #define WEBLAYER_PUBLIC_TAB_H_
#include <algorithm> #include <algorithm>
#include <string>
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
...@@ -75,6 +76,9 @@ class Tab { ...@@ -75,6 +76,9 @@ class Tab {
bool use_separate_isolate, bool use_separate_isolate,
JavaScriptResultCallback callback) = 0; JavaScriptResultCallback callback) = 0;
// Returns the tab's guid.
virtual const std::string& GetGuid() = 0;
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
// TODO: this isn't a stable API, so use it now for expediency in the C++ API, // TODO: this isn't a stable API, so use it now for expediency in the C++ API,
// but if we ever want to have backward or forward compatibility in C++ this // but if we ever want to have backward or forward compatibility in C++ this
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment