Commit 3692e6bb authored by Scott Violet's avatar Scott Violet Committed by Commit Bot

weblayer: adds API to know if Browser is restoring and when done

This way embedders have API to know when they can take action
based on whether restore has completed.

BUG=1135278
TEST=covered by tests

Change-Id: I72d804a86d8c4eeafdc3b72bbcf16875a78eb477
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2451550
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarClark DuVall <cduvall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#814450}
parent e995da4a
...@@ -299,6 +299,7 @@ source_set("weblayer_lib_base") { ...@@ -299,6 +299,7 @@ source_set("weblayer_lib_base") {
"public/browser.cc", "public/browser.cc",
"public/browser.h", "public/browser.h",
"public/browser_observer.h", "public/browser_observer.h",
"public/browser_restore_observer.h",
"public/common/switches.cc", "public/common/switches.cc",
"public/common/switches.h", "public/common/switches.h",
"public/cookie_manager.h", "public/cookie_manager.h",
......
...@@ -19,11 +19,13 @@ import org.junit.runner.RunWith; ...@@ -19,11 +19,13 @@ import org.junit.runner.RunWith;
import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CallbackHelper;
import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.weblayer.Browser; import org.chromium.weblayer.Browser;
import org.chromium.weblayer.BrowserRestoreCallback;
import org.chromium.weblayer.Navigation; import org.chromium.weblayer.Navigation;
import org.chromium.weblayer.NavigationCallback; import org.chromium.weblayer.NavigationCallback;
import org.chromium.weblayer.NavigationController; import org.chromium.weblayer.NavigationController;
import org.chromium.weblayer.Profile; import org.chromium.weblayer.Profile;
import org.chromium.weblayer.Tab; import org.chromium.weblayer.Tab;
import org.chromium.weblayer.WebLayer;
import org.chromium.weblayer.shell.InstrumentationActivity; import org.chromium.weblayer.shell.InstrumentationActivity;
import java.util.HashMap; import java.util.HashMap;
...@@ -45,6 +47,16 @@ public class BrowserFragmentLifecycleTest { ...@@ -45,6 +47,16 @@ public class BrowserFragmentLifecycleTest {
() -> mActivityTestRule.getActivity().getTab()); () -> mActivityTestRule.getActivity().getTab());
} }
private boolean isRestoringPreviousState() {
return TestThreadUtils.runOnUiThreadBlockingNoException(
() -> mActivityTestRule.getActivity().getBrowser().isRestoringPreviousState());
}
private int getSupportedMajorVersion() {
return TestThreadUtils.runOnUiThreadBlockingNoException(
() -> WebLayer.getSupportedMajorVersion(mActivityTestRule.getActivity()));
}
@Test @Test
@SmallTest @SmallTest
public void successfullyLoadsUrlAfterRecreation() { public void successfullyLoadsUrlAfterRecreation() {
...@@ -127,12 +139,18 @@ public class BrowserFragmentLifecycleTest { ...@@ -127,12 +139,18 @@ public class BrowserFragmentLifecycleTest {
extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, "x"); extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, "x");
final String url = mActivityTestRule.getTestDataURL("simple_page.html"); final String url = mActivityTestRule.getTestDataURL("simple_page.html");
mActivityTestRule.launchShellWithUrl(url, extras); mActivityTestRule.launchShellWithUrl(url, extras);
if (getSupportedMajorVersion() >= 88) {
Assert.assertFalse(isRestoringPreviousState());
}
mActivityTestRule.recreateActivity(); mActivityTestRule.recreateActivity();
Tab tab = getTab(); Tab tab = getTab();
Assert.assertNotNull(tab); Assert.assertNotNull(tab);
waitForTabToFinishRestore(tab, url); waitForTabToFinishRestore(tab, url);
if (getSupportedMajorVersion() >= 88) {
Assert.assertFalse(isRestoringPreviousState());
}
} }
@Test @Test
...@@ -201,7 +219,7 @@ public class BrowserFragmentLifecycleTest { ...@@ -201,7 +219,7 @@ public class BrowserFragmentLifecycleTest {
Map<String, String> initialData = new HashMap<>(); Map<String, String> initialData = new HashMap<>();
initialData.put("foo", "bar"); initialData.put("foo", "bar");
restoresTabData(extras, initialData); restoreTabData(extras, initialData);
} }
@Test @Test
...@@ -210,10 +228,10 @@ public class BrowserFragmentLifecycleTest { ...@@ -210,10 +228,10 @@ public class BrowserFragmentLifecycleTest {
public void restoreTabDataAfterRecreate() throws Throwable { public void restoreTabDataAfterRecreate() throws Throwable {
Map<String, String> initialData = new HashMap<>(); Map<String, String> initialData = new HashMap<>();
initialData.put("foo", "bar"); initialData.put("foo", "bar");
restoresTabData(new Bundle(), initialData); restoreTabData(new Bundle(), initialData);
} }
private void restoresTabData(Bundle extras, Map<String, String> initialData) { private void restoreTabData(Bundle extras, Map<String, String> initialData) {
String url = mActivityTestRule.getTestDataURL("simple_page.html"); String url = mActivityTestRule.getTestDataURL("simple_page.html");
mActivityTestRule.launchShellWithUrl(url, extras); mActivityTestRule.launchShellWithUrl(url, extras);
...@@ -304,4 +322,46 @@ public class BrowserFragmentLifecycleTest { ...@@ -304,4 +322,46 @@ public class BrowserFragmentLifecycleTest {
Assert.assertTrue(tab.isDestroyed()); Assert.assertTrue(tab.isDestroyed());
}); });
} }
@Test
@SmallTest
@MinWebLayerVersion(88)
public void restoreUsingOnRestoreCompleted() throws Throwable {
final String persistenceId = "x";
Bundle extras = new Bundle();
extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, persistenceId);
CallbackHelper callbackHelper = new CallbackHelper();
InstrumentationActivity.registerOnCreatedCallback(
new InstrumentationActivity.OnCreatedCallback() {
private int mBrowserCreateCount;
@Override
public void onCreated(Browser browser) {
if (mBrowserCreateCount == 0) {
// Initial creation.
mBrowserCreateCount = 1;
// isRestoringPreviousState() is true for the initial creation as
// persistence code has to check disk, which is async.
Assert.assertTrue(browser.isRestoringPreviousState());
} else if (mBrowserCreateCount == 1) {
// The activity was recreated.
mBrowserCreateCount = 2;
Assert.assertTrue(browser.isRestoringPreviousState());
browser.registerBrowserRestoreCallback(new BrowserRestoreCallback() {
@Override
public void onRestoreCompleted() {
Assert.assertFalse(browser.isRestoringPreviousState());
callbackHelper.notifyCalled();
}
});
} else {
Assert.fail("Unexpected phase");
}
}
});
final String url = mActivityTestRule.getTestDataURL("simple_page.html");
mActivityTestRule.launchShellWithUrl(url, extras);
mActivityTestRule.recreateActivity();
callbackHelper.waitForFirst();
}
} }
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "weblayer/browser/tab_impl.h" #include "weblayer/browser/tab_impl.h"
#include "weblayer/common/weblayer_paths.h" #include "weblayer/common/weblayer_paths.h"
#include "weblayer/public/browser_observer.h" #include "weblayer/public/browser_observer.h"
#include "weblayer/public/browser_restore_observer.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
#include "base/android/callback_android.h" #include "base/android/callback_android.h"
...@@ -329,6 +330,14 @@ Tab* BrowserImpl::CreateTab() { ...@@ -329,6 +330,14 @@ Tab* BrowserImpl::CreateTab() {
return CreateTab(nullptr); return CreateTab(nullptr);
} }
void BrowserImpl::OnRestoreCompleted() {
for (BrowserRestoreObserver& obs : browser_restore_observers_)
obs.OnRestoreCompleted();
#if defined(OS_ANDROID)
Java_BrowserImpl_onRestoreCompleted(AttachCurrentThread(), java_impl_);
#endif
}
void BrowserImpl::PrepareForShutdown() { void BrowserImpl::PrepareForShutdown() {
browser_persister_.reset(); browser_persister_.reset();
} }
...@@ -342,6 +351,10 @@ std::vector<uint8_t> BrowserImpl::GetMinimalPersistenceState() { ...@@ -342,6 +351,10 @@ std::vector<uint8_t> BrowserImpl::GetMinimalPersistenceState() {
return GetMinimalPersistenceState(0); return GetMinimalPersistenceState(0);
} }
bool BrowserImpl::IsRestoringPreviousState() {
return browser_persister_ && browser_persister_->is_restore_in_progress();
}
void BrowserImpl::AddObserver(BrowserObserver* observer) { void BrowserImpl::AddObserver(BrowserObserver* observer) {
browser_observers_.AddObserver(observer); browser_observers_.AddObserver(observer);
} }
...@@ -350,6 +363,15 @@ void BrowserImpl::RemoveObserver(BrowserObserver* observer) { ...@@ -350,6 +363,15 @@ void BrowserImpl::RemoveObserver(BrowserObserver* observer) {
browser_observers_.RemoveObserver(observer); browser_observers_.RemoveObserver(observer);
} }
void BrowserImpl::AddBrowserRestoreObserver(BrowserRestoreObserver* observer) {
browser_restore_observers_.AddObserver(observer);
}
void BrowserImpl::RemoveBrowserRestoreObserver(
BrowserRestoreObserver* observer) {
browser_restore_observers_.RemoveObserver(observer);
}
void BrowserImpl::VisibleSecurityStateOfActiveTabChanged() { void BrowserImpl::VisibleSecurityStateOfActiveTabChanged() {
if (visible_security_state_changed_callback_for_tests_) if (visible_security_state_changed_callback_for_tests_)
std::move(visible_security_state_changed_callback_for_tests_).Run(); std::move(visible_security_state_changed_callback_for_tests_).Run();
......
...@@ -57,6 +57,9 @@ class BrowserImpl : public Browser { ...@@ -57,6 +57,9 @@ class BrowserImpl : public Browser {
const std::string& guid); const std::string& guid);
TabImpl* CreateTab(std::unique_ptr<content::WebContents> web_contents); TabImpl* CreateTab(std::unique_ptr<content::WebContents> web_contents);
// Called from BrowserPersister when restore has completed.
void OnRestoreCompleted();
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
bool CompositorHasSurface(); bool CompositorHasSurface();
...@@ -83,6 +86,9 @@ class BrowserImpl : public Browser { ...@@ -83,6 +86,9 @@ class BrowserImpl : public Browser {
void OnFragmentStart(JNIEnv* env); void OnFragmentStart(JNIEnv* env);
void OnFragmentResume(JNIEnv* env); void OnFragmentResume(JNIEnv* env);
void OnFragmentPause(JNIEnv* env); void OnFragmentPause(JNIEnv* env);
bool IsRestoringPreviousState(JNIEnv* env) {
return IsRestoringPreviousState();
}
bool fragment_resumed() { return fragment_resumed_; } bool fragment_resumed() { return fragment_resumed_; }
#endif #endif
...@@ -118,8 +124,11 @@ class BrowserImpl : public Browser { ...@@ -118,8 +124,11 @@ class BrowserImpl : public Browser {
void PrepareForShutdown() override; void PrepareForShutdown() override;
std::string GetPersistenceId() override; std::string GetPersistenceId() override;
std::vector<uint8_t> GetMinimalPersistenceState() override; std::vector<uint8_t> GetMinimalPersistenceState() override;
bool IsRestoringPreviousState() override;
void AddObserver(BrowserObserver* observer) override; void AddObserver(BrowserObserver* observer) override;
void RemoveObserver(BrowserObserver* observer) override; void RemoveObserver(BrowserObserver* observer) override;
void AddBrowserRestoreObserver(BrowserRestoreObserver* observer) override;
void RemoveBrowserRestoreObserver(BrowserRestoreObserver* observer) override;
void VisibleSecurityStateOfActiveTabChanged() override; void VisibleSecurityStateOfActiveTabChanged() override;
private: private:
...@@ -149,6 +158,7 @@ class BrowserImpl : public Browser { ...@@ -149,6 +158,7 @@ class BrowserImpl : public Browser {
base::android::ScopedJavaGlobalRef<jobject> java_impl_; base::android::ScopedJavaGlobalRef<jobject> java_impl_;
#endif #endif
base::ObserverList<BrowserObserver> browser_observers_; base::ObserverList<BrowserObserver> browser_observers_;
base::ObserverList<BrowserRestoreObserver> browser_restore_observers_;
ProfileImpl* const profile_; ProfileImpl* const profile_;
std::vector<std::unique_ptr<Tab>> tabs_; std::vector<std::unique_ptr<Tab>> tabs_;
TabImpl* active_tab_ = nullptr; TabImpl* active_tab_ = nullptr;
......
...@@ -494,6 +494,16 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan ...@@ -494,6 +494,16 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
} }
} }
@Override
public boolean isRestoringPreviousState() {
return BrowserImplJni.get().isRestoringPreviousState(mNativeBrowser);
}
@CalledByNative
private void onRestoreCompleted() throws RemoteException {
mClient.onRestoreCompleted();
}
public View getFragmentView() { public View getFragmentView() {
return getViewController().getView(); return getViewController().getView();
} }
...@@ -645,5 +655,6 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan ...@@ -645,5 +655,6 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
void onFragmentStart(long nativeBrowserImpl); void onFragmentStart(long nativeBrowserImpl);
void onFragmentResume(long nativeBrowserImpl); void onFragmentResume(long nativeBrowserImpl);
void onFragmentPause(long nativeBrowserImpl); void onFragmentPause(long nativeBrowserImpl);
boolean isRestoringPreviousState(long nativeBrowserImpl);
} }
} }
...@@ -43,4 +43,7 @@ interface IBrowser { ...@@ -43,4 +43,7 @@ interface IBrowser {
// Added in 87. // Added in 87.
void setBrowserControlsOffsetsEnabled(in boolean enable) = 13; void setBrowserControlsOffsetsEnabled(in boolean enable) = 13;
// Added in 88.
boolean isRestoringPreviousState() = 14;
} }
...@@ -16,4 +16,7 @@ interface IBrowserClient { ...@@ -16,4 +16,7 @@ interface IBrowserClient {
IRemoteFragment createMediaRouteDialogFragment() = 3; IRemoteFragment createMediaRouteDialogFragment() = 3;
void onBrowserControlsOffsetsChanged(in boolean isTop, void onBrowserControlsOffsetsChanged(in boolean isTop,
in int controlsOffset) = 4; in int controlsOffset) = 4;
// Added in 88.
void onRestoreCompleted() = 5;
} }
...@@ -277,6 +277,9 @@ void BrowserPersister::OnGotCurrentSessionCommands( ...@@ -277,6 +277,9 @@ void BrowserPersister::OnGotCurrentSessionCommands(
ScheduleRebuildOnNextSave(); ScheduleRebuildOnNextSave();
RestoreBrowserState(browser_, std::move(commands)); RestoreBrowserState(browser_, std::move(commands));
is_restore_in_progress_ = false;
browser_->OnRestoreCompleted();
} }
void BrowserPersister::BuildCommandsForTab(TabImpl* tab, int index_in_browser) { void BrowserPersister::BuildCommandsForTab(TabImpl* tab, int index_in_browser) {
......
...@@ -53,6 +53,8 @@ class BrowserPersister : public sessions::CommandStorageManagerDelegate, ...@@ -53,6 +53,8 @@ class BrowserPersister : public sessions::CommandStorageManagerDelegate,
~BrowserPersister() override; ~BrowserPersister() override;
bool is_restore_in_progress() const { return is_restore_in_progress_; }
void SaveIfNecessary(); void SaveIfNecessary();
// Returns the key used to encrypt the file. Empty if not encrypted. // Returns the key used to encrypt the file. Empty if not encrypted.
...@@ -139,6 +141,9 @@ class BrowserPersister : public sessions::CommandStorageManagerDelegate, ...@@ -139,6 +141,9 @@ class BrowserPersister : public sessions::CommandStorageManagerDelegate,
&TabImpl::RemoveDataObserver> &TabImpl::RemoveDataObserver>
data_observer_{this}; data_observer_{this};
// True while asynchronously reading the state to restore.
bool is_restore_in_progress_ = true;
base::WeakPtrFactory<BrowserPersister> weak_factory_{this}; base::WeakPtrFactory<BrowserPersister> weak_factory_{this};
}; };
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "weblayer/browser/profile_impl.h" #include "weblayer/browser/profile_impl.h"
#include "weblayer/browser/tab_impl.h" #include "weblayer/browser/tab_impl.h"
#include "weblayer/common/weblayer_paths.h" #include "weblayer/common/weblayer_paths.h"
#include "weblayer/public/browser_restore_observer.h"
#include "weblayer/public/navigation.h" #include "weblayer/public/navigation.h"
#include "weblayer/public/navigation_controller.h" #include "weblayer/public/navigation_controller.h"
#include "weblayer/public/navigation_observer.h" #include "weblayer/public/navigation_observer.h"
...@@ -47,34 +48,12 @@ class BrowserPersisterTestHelper { ...@@ -47,34 +48,12 @@ class BrowserPersisterTestHelper {
namespace { namespace {
using testing::UnorderedElementsAre; using testing::UnorderedElementsAre;
class BrowserObserverImpl : public BrowserObserver { class BrowserNavigationObserverImpl : public BrowserRestoreObserver,
public:
static void WaitForNewTab(Browser* browser) {
BrowserObserverImpl observer(browser);
observer.Wait();
}
private:
explicit BrowserObserverImpl(Browser* browser) : browser_(browser) {
browser_->AddObserver(this);
}
~BrowserObserverImpl() override { browser_->RemoveObserver(this); }
void Wait() { run_loop_.Run(); }
// BrowserObserver:
void OnTabAdded(Tab* tab) override { run_loop_.Quit(); }
Browser* browser_;
base::RunLoop run_loop_;
};
class BrowserNavigationObserverImpl : public BrowserObserver,
public NavigationObserver { public NavigationObserver {
public: public:
static void WaitForNewTabToCompleteNavigation(Browser* browser, static void WaitForNewTabToCompleteNavigation(Browser* browser,
const GURL& url, const GURL& url,
int tab_to_wait_for = 1) { size_t tab_to_wait_for = 0) {
BrowserNavigationObserverImpl observer(browser, url, tab_to_wait_for); BrowserNavigationObserverImpl observer(browser, url, tab_to_wait_for);
observer.Wait(); observer.Wait();
} }
...@@ -82,9 +61,9 @@ class BrowserNavigationObserverImpl : public BrowserObserver, ...@@ -82,9 +61,9 @@ class BrowserNavigationObserverImpl : public BrowserObserver,
private: private:
BrowserNavigationObserverImpl(Browser* browser, BrowserNavigationObserverImpl(Browser* browser,
const GURL& url, const GURL& url,
int tab_to_wait_for) size_t tab_to_wait_for)
: browser_(browser), url_(url), tab_to_wait_for_(tab_to_wait_for) { : browser_(browser), url_(url), tab_to_wait_for_(tab_to_wait_for) {
browser_->AddObserver(this); browser_->AddBrowserRestoreObserver(this);
} }
~BrowserNavigationObserverImpl() override { ~BrowserNavigationObserverImpl() override {
tab_->GetNavigationController()->RemoveObserver(this); tab_->GetNavigationController()->RemoveObserver(this);
...@@ -98,20 +77,19 @@ class BrowserNavigationObserverImpl : public BrowserObserver, ...@@ -98,20 +77,19 @@ class BrowserNavigationObserverImpl : public BrowserObserver,
run_loop_.Quit(); run_loop_.Quit();
} }
// BrowserObserver: // BrowserRestoreObserver:
void OnTabAdded(Tab* tab) override { void OnRestoreCompleted() override {
if (--tab_to_wait_for_ != 0) browser_->RemoveBrowserRestoreObserver(this);
return; ASSERT_LT(tab_to_wait_for_, browser_->GetTabs().size());
ASSERT_EQ(nullptr, tab_);
browser_->RemoveObserver(this); tab_ = browser_->GetTabs()[tab_to_wait_for_];
tab_ = tab;
tab_->GetNavigationController()->AddObserver(this); tab_->GetNavigationController()->AddObserver(this);
} }
Browser* browser_; Browser* browser_;
const GURL& url_; const GURL& url_;
Tab* tab_ = nullptr; Tab* tab_ = nullptr;
int tab_to_wait_for_; const size_t tab_to_wait_for_;
std::unique_ptr<TestNavigationObserver> navigation_observer_; std::unique_ptr<TestNavigationObserver> navigation_observer_;
base::RunLoop run_loop_; base::RunLoop run_loop_;
}; };
...@@ -146,6 +124,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, SingleTab) { ...@@ -146,6 +124,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, SingleTab) {
std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x"); std::unique_ptr<BrowserImpl> browser = CreateBrowser(GetProfile(), "x");
Tab* tab = browser->CreateTab(); Tab* tab = browser->CreateTab();
EXPECT_TRUE(browser->IsRestoringPreviousState());
const GURL url = embedded_test_server()->GetURL("/simple_page.html"); const GURL url = embedded_test_server()->GetURL("/simple_page.html");
NavigateAndWaitForCompletion(url, tab); NavigateAndWaitForCompletion(url, tab);
ShutdownBrowserPersisterAndWait(browser.get()); ShutdownBrowserPersisterAndWait(browser.get());
...@@ -155,6 +134,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, SingleTab) { ...@@ -155,6 +134,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, SingleTab) {
browser = CreateBrowser(GetProfile(), "x"); browser = CreateBrowser(GetProfile(), "x");
// Should be no tabs while waiting for restore. // Should be no tabs while waiting for restore.
EXPECT_TRUE(browser->GetTabs().empty()); EXPECT_TRUE(browser->GetTabs().empty());
EXPECT_TRUE(browser->IsRestoringPreviousState());
// Wait for the restore and navigation to complete. // Wait for the restore and navigation to complete.
BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation( BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
browser.get(), url); browser.get(), url);
...@@ -164,6 +144,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, SingleTab) { ...@@ -164,6 +144,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, SingleTab) {
EXPECT_EQ(1, browser->GetTabs()[0] EXPECT_EQ(1, browser->GetTabs()[0]
->GetNavigationController() ->GetNavigationController()
->GetNavigationListSize()); ->GetNavigationListSize());
EXPECT_FALSE(browser->IsRestoringPreviousState());
} }
IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, RestoresGuid) { IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, RestoresGuid) {
...@@ -276,7 +257,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, TwoTabs) { ...@@ -276,7 +257,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, TwoTabs) {
// Wait for the restore and navigation to complete. This waits for the // Wait for the restore and navigation to complete. This waits for the
// second tab as that was the active one. // second tab as that was the active one.
BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation( BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
browser.get(), url2, 2); browser.get(), url2, 1);
ASSERT_EQ(2u, browser->GetTabs().size()) << "iteration " << i; ASSERT_EQ(2u, browser->GetTabs().size()) << "iteration " << i;
// The first tab shouldn't have loaded yet, as it's not active. // The first tab shouldn't have loaded yet, as it's not active.
...@@ -331,7 +312,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, MoveBetweenBrowsers) { ...@@ -331,7 +312,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, MoveBetweenBrowsers) {
// Restore the browsers. // Restore the browsers.
browser1 = CreateBrowser(GetProfile(), "x"); browser1 = CreateBrowser(GetProfile(), "x");
BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation( BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
browser1.get(), url1, 1); browser1.get(), url1);
ASSERT_EQ(1u, browser1->GetTabs().size()); ASSERT_EQ(1u, browser1->GetTabs().size());
EXPECT_EQ(1, browser1->GetTabs()[0] EXPECT_EQ(1, browser1->GetTabs()[0]
->GetNavigationController() ->GetNavigationController()
...@@ -339,7 +320,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, MoveBetweenBrowsers) { ...@@ -339,7 +320,7 @@ IN_PROC_BROWSER_TEST_F(BrowserPersisterTest, MoveBetweenBrowsers) {
browser2 = CreateBrowser(GetProfile(), "y"); browser2 = CreateBrowser(GetProfile(), "y");
BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation( BrowserNavigationObserverImpl::WaitForNewTabToCompleteNavigation(
browser2.get(), url2, 2); browser2.get(), url2, 1);
ASSERT_EQ(2u, browser2->GetTabs().size()); ASSERT_EQ(2u, browser2->GetTabs().size());
EXPECT_EQ(1, browser2->GetTabs()[1] EXPECT_EQ(1, browser2->GetTabs()[1]
->GetNavigationController() ->GetNavigationController()
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
namespace weblayer { namespace weblayer {
class BrowserObserver; class BrowserObserver;
class BrowserRestoreObserver;
class Profile; class Profile;
class Tab; class Tab;
...@@ -68,9 +69,18 @@ class Browser { ...@@ -68,9 +69,18 @@ class Browser {
// lightweight restore when full persistence is not desirable. // lightweight restore when full persistence is not desirable.
virtual std::vector<uint8_t> GetMinimalPersistenceState() = 0; virtual std::vector<uint8_t> GetMinimalPersistenceState() = 0;
// Returns true if this Browser is in the process of restoring the previous
// state. That is, PersistenceInfo was supplied to the constructor and
// the state is asynchronously being loaded.
virtual bool IsRestoringPreviousState() = 0;
virtual void AddObserver(BrowserObserver* observer) = 0; virtual void AddObserver(BrowserObserver* observer) = 0;
virtual void RemoveObserver(BrowserObserver* observer) = 0; virtual void RemoveObserver(BrowserObserver* observer) = 0;
virtual void AddBrowserRestoreObserver(BrowserRestoreObserver* observer) = 0;
virtual void RemoveBrowserRestoreObserver(
BrowserRestoreObserver* observer) = 0;
virtual void VisibleSecurityStateOfActiveTabChanged() = 0; virtual void VisibleSecurityStateOfActiveTabChanged() = 0;
}; };
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WEBLAYER_PUBLIC_BROWSER_RESTORE_OBSERVER_H_
#define WEBLAYER_PUBLIC_BROWSER_RESTORE_OBSERVER_H_
#include "base/observer_list.h"
namespace weblayer {
// Used for observing events related to restoring the previous state of a
// Browser.
class BrowserRestoreObserver : public base::CheckedObserver {
public:
// Called when the Browser has completed restoring the previous state.
virtual void OnRestoreCompleted() {}
protected:
~BrowserRestoreObserver() override = default;
};
} // namespace weblayer
#endif // WEBLAYER_PUBLIC_BROWSER_RESTORE_OBSERVER_H_
...@@ -39,6 +39,7 @@ android_library("java") { ...@@ -39,6 +39,7 @@ android_library("java") {
"org/chromium/weblayer/Browser.java", "org/chromium/weblayer/Browser.java",
"org/chromium/weblayer/BrowserControlsOffsetCallback.java", "org/chromium/weblayer/BrowserControlsOffsetCallback.java",
"org/chromium/weblayer/BrowserFragment.java", "org/chromium/weblayer/BrowserFragment.java",
"org/chromium/weblayer/BrowserRestoreCallback.java",
"org/chromium/weblayer/BrowsingDataType.java", "org/chromium/weblayer/BrowsingDataType.java",
"org/chromium/weblayer/Callback.java", "org/chromium/weblayer/Callback.java",
"org/chromium/weblayer/CaptureScreenShotCallback.java", "org/chromium/weblayer/CaptureScreenShotCallback.java",
......
...@@ -36,6 +36,7 @@ public class Browser { ...@@ -36,6 +36,7 @@ public class Browser {
private final UrlBarController mUrlBarController; private final UrlBarController mUrlBarController;
private final ObserverList<BrowserControlsOffsetCallback> mBrowserControlsOffsetCallbacks; private final ObserverList<BrowserControlsOffsetCallback> mBrowserControlsOffsetCallbacks;
private final ObserverList<BrowserRestoreCallback> mBrowserRestoreCallbacks;
// Constructor for test mocking. // Constructor for test mocking.
protected Browser() { protected Browser() {
...@@ -43,6 +44,7 @@ public class Browser { ...@@ -43,6 +44,7 @@ public class Browser {
mTabListCallbacks = null; mTabListCallbacks = null;
mUrlBarController = null; mUrlBarController = null;
mBrowserControlsOffsetCallbacks = null; mBrowserControlsOffsetCallbacks = null;
mBrowserRestoreCallbacks = null;
} }
Browser(IBrowser impl, BrowserFragment fragment) { Browser(IBrowser impl, BrowserFragment fragment) {
...@@ -50,6 +52,7 @@ public class Browser { ...@@ -50,6 +52,7 @@ public class Browser {
mFragment = fragment; mFragment = fragment;
mTabListCallbacks = new ObserverList<TabListCallback>(); mTabListCallbacks = new ObserverList<TabListCallback>();
mBrowserControlsOffsetCallbacks = new ObserverList<BrowserControlsOffsetCallback>(); mBrowserControlsOffsetCallbacks = new ObserverList<BrowserControlsOffsetCallback>();
mBrowserRestoreCallbacks = new ObserverList<BrowserRestoreCallback>();
try { try {
mImpl.setClient(new BrowserClientImpl()); mImpl.setClient(new BrowserClientImpl());
...@@ -220,6 +223,58 @@ public class Browser { ...@@ -220,6 +223,58 @@ public class Browser {
mTabListCallbacks.removeObserver(callback); mTabListCallbacks.removeObserver(callback);
} }
/**
* Returns true if this Browser is in the process of restoring the previous state.
*
* @param True if restoring previous state.
*
* @since 88
*/
public boolean isRestoringPreviousState() {
ThreadCheck.ensureOnUiThread();
if (WebLayer.getSupportedMajorVersionInternal() < 88) {
throw new UnsupportedOperationException();
}
throwIfDestroyed();
try {
return mImpl.isRestoringPreviousState();
} catch (RemoteException e) {
throw new APICallException(e);
}
}
/**
* Adds a BrowserRestoreCallback.
*
* @param callback The BrowserRestoreCallback.
*
* @since 88
*/
public void registerBrowserRestoreCallback(@NonNull BrowserRestoreCallback callback) {
ThreadCheck.ensureOnUiThread();
if (WebLayer.getSupportedMajorVersionInternal() < 88) {
throw new UnsupportedOperationException();
}
throwIfDestroyed();
mBrowserRestoreCallbacks.addObserver(callback);
}
/**
* Removes a BrowserRestoreCallback.
*
* @param callback The BrowserRestoreCallback.
*
* @since 88
*/
public void unregisterBrowserRestoreCallback(@NonNull BrowserRestoreCallback callback) {
ThreadCheck.ensureOnUiThread();
if (WebLayer.getSupportedMajorVersionInternal() < 88) {
throw new UnsupportedOperationException();
}
throwIfDestroyed();
mBrowserRestoreCallbacks.removeObserver(callback);
}
/** /**
* Sets the View shown at the top of the browser. A value of null removes the view. The * Sets the View shown at the top of the browser. A value of null removes the view. The
* top-view is typically used to show the uri. The top-view scrolls with the page. * top-view is typically used to show the uri. The top-view scrolls with the page.
...@@ -467,5 +522,12 @@ public class Browser { ...@@ -467,5 +522,12 @@ public class Browser {
} }
} }
} }
@Override
public void onRestoreCompleted() {
for (BrowserRestoreCallback callback : mBrowserRestoreCallbacks) {
callback.onRestoreCompleted();
}
}
} }
} }
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.weblayer;
/**
* An interface for observing events related to restoring the previous state of a Browser.
*
* @since 88
*/
public abstract class BrowserRestoreCallback {
/**
* Called when WebLayer has finished restoring the previous state.
*/
public void onRestoreCompleted() {}
}
...@@ -58,6 +58,8 @@ public class InstrumentationActivity extends FragmentActivity { ...@@ -58,6 +58,8 @@ public class InstrumentationActivity extends FragmentActivity {
// that show Page Info UI on its TextView. // that show Page Info UI on its TextView.
public static final String EXTRA_URLBAR_TEXT_CLICKABLE = "EXTRA_URLBAR_TEXT_CLICKABLE"; public static final String EXTRA_URLBAR_TEXT_CLICKABLE = "EXTRA_URLBAR_TEXT_CLICKABLE";
private static OnCreatedCallback sOnCreatedCallback;
private Profile mProfile; private Profile mProfile;
private Fragment mFragment; private Fragment mFragment;
private Browser mBrowser; private Browser mBrowser;
...@@ -85,6 +87,25 @@ public class InstrumentationActivity extends FragmentActivity { ...@@ -85,6 +87,25 @@ public class InstrumentationActivity extends FragmentActivity {
return false; return false;
} }
/**
* Use this callback for tests that need to be notified synchronously when the Browser has been
* created.
*/
public static interface OnCreatedCallback {
// Notification that a Browser was created.
// This is called on the UI thread.
public void onCreated(Browser browser);
}
// Registers a callback that is notified on the UI thread when a Browser is created.
public static void registerOnCreatedCallback(OnCreatedCallback callback) {
sOnCreatedCallback = callback;
// Ideally |callback| would be registered in the Intent, but that isn't possible as to do so
// |callback| would have to be a Parceable (which doesn't make sense). As at this time each
// test runs in its own process a static is used, if multiple tests were to run in the same
// binary, then some state would need to be put in the intent.
}
public Tab getTab() { public Tab getTab() {
return mTab; return mTab;
} }
...@@ -292,6 +313,12 @@ public class InstrumentationActivity extends FragmentActivity { ...@@ -292,6 +313,12 @@ public class InstrumentationActivity extends FragmentActivity {
setTabCallbacks(mBrowser.getActiveTab()); setTabCallbacks(mBrowser.getActiveTab());
setTab(mBrowser.getActiveTab()); setTab(mBrowser.getActiveTab());
} }
if (sOnCreatedCallback != null) {
sOnCreatedCallback.onCreated(mBrowser);
// Don't reset |sOnCreatedCallback| as it's needed for tests that exercise activity
// recreation.
}
} }
private void setTabCallbacks(Tab tab) { private void setTabCallbacks(Tab tab) {
......
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