1 // Copyright 2019 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.weblayer.test; 6 7 import android.content.Intent; 8 import android.net.Uri; 9 import android.os.Bundle; 10 11 import androidx.annotation.NonNull; 12 import androidx.fragment.app.FragmentManager; 13 import androidx.test.filters.SmallTest; 14 15 import org.junit.Assert; 16 import org.junit.Rule; 17 import org.junit.Test; 18 import org.junit.runner.RunWith; 19 20 import org.chromium.base.test.util.CallbackHelper; 21 import org.chromium.content_public.browser.test.util.TestThreadUtils; 22 import org.chromium.weblayer.Browser; 23 import org.chromium.weblayer.BrowserRestoreCallback; 24 import org.chromium.weblayer.Navigation; 25 import org.chromium.weblayer.NavigationCallback; 26 import org.chromium.weblayer.NavigationController; 27 import org.chromium.weblayer.Profile; 28 import org.chromium.weblayer.Tab; 29 import org.chromium.weblayer.WebLayer; 30 import org.chromium.weblayer.shell.InstrumentationActivity; 31 32 import java.util.ArrayList; 33 import java.util.HashMap; 34 import java.util.HashSet; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.Set; 38 39 /** 40 * Tests that fragment lifecycle works as expected. 41 */ 42 @RunWith(WebLayerJUnit4ClassRunner.class) 43 public class BrowserFragmentLifecycleTest { 44 @Rule 45 public InstrumentationActivityTestRule mActivityTestRule = 46 new InstrumentationActivityTestRule(); 47 getTab()48 private Tab getTab() { 49 return TestThreadUtils.runOnUiThreadBlockingNoException( 50 () -> mActivityTestRule.getActivity().getTab()); 51 } 52 isRestoringPreviousState()53 private boolean isRestoringPreviousState() { 54 return TestThreadUtils.runOnUiThreadBlockingNoException( 55 () -> mActivityTestRule.getActivity().getBrowser().isRestoringPreviousState()); 56 } 57 getSupportedMajorVersion()58 private int getSupportedMajorVersion() { 59 return TestThreadUtils.runOnUiThreadBlockingNoException( 60 () -> WebLayer.getSupportedMajorVersion(mActivityTestRule.getActivity())); 61 } 62 63 @Test 64 @SmallTest successfullyLoadsUrlAfterRecreation()65 public void successfullyLoadsUrlAfterRecreation() { 66 mActivityTestRule.launchShellWithUrl("about:blank"); 67 String url = "data:text,foo"; 68 mActivityTestRule.navigateAndWait(getTab(), url, false); 69 70 mActivityTestRule.recreateActivity(); 71 72 url = "data:text,bar"; 73 mActivityTestRule.navigateAndWait(getTab(), url, false); 74 } 75 76 @Test 77 @SmallTest restoreAfterRecreate()78 public void restoreAfterRecreate() throws Throwable { 79 mActivityTestRule.launchShellWithUrl("about:blank"); 80 String url = "data:text,foo"; 81 mActivityTestRule.navigateAndWait(getTab(), url, false); 82 83 mActivityTestRule.recreateActivity(); 84 85 waitForTabToFinishRestore(getTab(), url); 86 } 87 destroyFragment(CallbackHelper helper)88 private void destroyFragment(CallbackHelper helper) { 89 FragmentManager fm = mActivityTestRule.getActivity().getSupportFragmentManager(); 90 fm.beginTransaction() 91 .remove(fm.getFragments().get(0)) 92 .runOnCommit(helper::notifyCalled) 93 .commit(); 94 } 95 96 // https://crbug.com/1021041 97 @Test 98 @SmallTest handlesFragmentDestroyWhileNavigating()99 public void handlesFragmentDestroyWhileNavigating() throws Throwable { 100 InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl("about:blank"); 101 CallbackHelper helper = new CallbackHelper(); 102 TestThreadUtils.runOnUiThreadBlocking(() -> { 103 NavigationController navigationController = activity.getTab().getNavigationController(); 104 navigationController.registerNavigationCallback(new NavigationCallback() { 105 @Override 106 public void onReadyToCommitNavigation(@NonNull Navigation navigation) { 107 destroyFragment(helper); 108 } 109 }); 110 navigationController.navigate(Uri.parse("data:text,foo")); 111 }); 112 helper.waitForFirst(); 113 } 114 115 // Waits for |tab| to finish loadding |url. This is intended to be called after restore. waitForTabToFinishRestore(Tab tab, String url)116 private void waitForTabToFinishRestore(Tab tab, String url) { 117 BoundedCountDownLatch latch = new BoundedCountDownLatch(1); 118 TestThreadUtils.runOnUiThreadBlocking(() -> { 119 // It's possible the NavigationController hasn't loaded yet, handle either scenario. 120 NavigationController navigationController = tab.getNavigationController(); 121 for (int i = 0; i < navigationController.getNavigationListSize(); ++i) { 122 if (navigationController.getNavigationEntryDisplayUri(i).equals(Uri.parse(url))) { 123 latch.countDown(); 124 return; 125 } 126 } 127 navigationController.registerNavigationCallback(new NavigationCallback() { 128 @Override 129 public void onNavigationCompleted(@NonNull Navigation navigation) { 130 if (navigation.getUri().equals(Uri.parse(url))) { 131 latch.countDown(); 132 } 133 } 134 }); 135 }); 136 latch.timedAwait(); 137 } 138 139 // Recreates the activity and waits for the first tab to be restored. |extras| is the Bundle 140 // used to launch the shell. restoresPreviousSession(Bundle extras)141 private void restoresPreviousSession(Bundle extras) { 142 extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, "x"); 143 final String url = mActivityTestRule.getTestDataURL("simple_page.html"); 144 mActivityTestRule.launchShellWithUrl(url, extras); 145 if (getSupportedMajorVersion() >= 88) { 146 Assert.assertFalse(isRestoringPreviousState()); 147 } 148 149 mActivityTestRule.recreateActivity(); 150 151 Tab tab = getTab(); 152 Assert.assertNotNull(tab); 153 waitForTabToFinishRestore(tab, url); 154 if (getSupportedMajorVersion() >= 88) { 155 Assert.assertFalse(isRestoringPreviousState()); 156 } 157 } 158 159 @Test 160 @SmallTest restoresPreviousSession()161 public void restoresPreviousSession() throws Throwable { 162 restoresPreviousSession(new Bundle()); 163 } 164 165 @Test 166 @SmallTest restoresPreviousSessionIncognito()167 public void restoresPreviousSessionIncognito() throws Throwable { 168 Bundle extras = new Bundle(); 169 // This forces incognito. 170 extras.putString(InstrumentationActivity.EXTRA_PROFILE_NAME, null); 171 restoresPreviousSession(extras); 172 } 173 174 @Test 175 @SmallTest restoresTabGuid()176 public void restoresTabGuid() throws Throwable { 177 Bundle extras = new Bundle(); 178 extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, "x"); 179 final String url = mActivityTestRule.getTestDataURL("simple_page.html"); 180 mActivityTestRule.launchShellWithUrl(url, extras); 181 final String initialTabId = TestThreadUtils.runOnUiThreadBlocking( 182 () -> { return mActivityTestRule.getActivity().getTab().getGuid(); }); 183 Assert.assertNotNull(initialTabId); 184 Assert.assertFalse(initialTabId.isEmpty()); 185 186 mActivityTestRule.recreateActivity(); 187 188 Tab tab = getTab(); 189 Assert.assertNotNull(tab); 190 waitForTabToFinishRestore(tab, url); 191 final String restoredTabId = 192 TestThreadUtils.runOnUiThreadBlockingNoException(() -> { return tab.getGuid(); }); 193 Assert.assertEquals(initialTabId, restoredTabId); 194 } 195 196 @Test 197 @SmallTest restoreTabGuidAfterRecreate()198 public void restoreTabGuidAfterRecreate() throws Throwable { 199 InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl("about:blank"); 200 final Tab tab = getTab(); 201 final String initialTabId = 202 TestThreadUtils.runOnUiThreadBlocking(() -> { return tab.getGuid(); }); 203 String url = "data:text,foo"; 204 mActivityTestRule.navigateAndWait(tab, url, false); 205 206 mActivityTestRule.recreateActivity(); 207 208 final Tab restoredTab = getTab(); 209 Assert.assertNotEquals(tab, restoredTab); 210 waitForTabToFinishRestore(restoredTab, url); 211 final String restoredTabId = TestThreadUtils.runOnUiThreadBlockingNoException( 212 () -> { return restoredTab.getGuid(); }); 213 Assert.assertEquals(initialTabId, restoredTabId); 214 } 215 216 @Test 217 @SmallTest 218 @MinWebLayerVersion(85) restoresTabData()219 public void restoresTabData() throws Throwable { 220 Bundle extras = new Bundle(); 221 extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, "x"); 222 223 Map<String, String> initialData = new HashMap<>(); 224 initialData.put("foo", "bar"); 225 restoreTabData(extras, initialData); 226 } 227 228 @Test 229 @SmallTest 230 @MinWebLayerVersion(85) restoreTabDataAfterRecreate()231 public void restoreTabDataAfterRecreate() throws Throwable { 232 Map<String, String> initialData = new HashMap<>(); 233 initialData.put("foo", "bar"); 234 restoreTabData(new Bundle(), initialData); 235 } 236 restoreTabData(Bundle extras, Map<String, String> initialData)237 private void restoreTabData(Bundle extras, Map<String, String> initialData) { 238 String url = mActivityTestRule.getTestDataURL("simple_page.html"); 239 mActivityTestRule.launchShellWithUrl(url, extras); 240 241 TestThreadUtils.runOnUiThreadBlocking(() -> { 242 Tab tab = mActivityTestRule.getActivity().getTab(); 243 Assert.assertTrue(tab.getData().isEmpty()); 244 tab.setData(initialData); 245 }); 246 247 mActivityTestRule.recreateActivity(); 248 249 Tab tab = getTab(); 250 Assert.assertNotNull(tab); 251 waitForTabToFinishRestore(tab, url); 252 TestThreadUtils.runOnUiThreadBlocking( 253 () -> Assert.assertEquals(initialData, tab.getData())); 254 } 255 256 @Test 257 @SmallTest 258 @MinWebLayerVersion(85) getAndRemoveBrowserPersistenceIds()259 public void getAndRemoveBrowserPersistenceIds() throws Throwable { 260 // Creates a browser with the persistence id 'x'. 261 final String persistenceId = "x"; 262 Bundle extras = new Bundle(); 263 extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, persistenceId); 264 final String url = mActivityTestRule.getTestDataURL("simple_page.html"); 265 mActivityTestRule.launchShellWithUrl(url, extras); 266 267 // Destroy the frament, which ensures the persistence file was written to. 268 CallbackHelper helper = new CallbackHelper(); 269 Profile profile = TestThreadUtils.runOnUiThreadBlocking( 270 () -> { return mActivityTestRule.getActivity().getBrowser().getProfile(); }); 271 TestThreadUtils.runOnUiThreadBlocking(() -> destroyFragment(helper)); 272 helper.waitForCallback(0, 1); 273 int callCount = helper.getCallCount(); 274 275 // Verify the id can be fetched. 276 TestThreadUtils.runOnUiThreadBlocking(() -> { 277 profile.getBrowserPersistenceIds((Set<String> ids) -> { 278 Assert.assertEquals(1, ids.size()); 279 Assert.assertTrue(ids.contains(persistenceId)); 280 helper.notifyCalled(); 281 }); 282 }); 283 helper.waitForCallback(callCount, 1); 284 callCount = helper.getCallCount(); 285 286 // Remove the storage. 287 HashSet<String> ids = new HashSet<String>(); 288 ids.add("x"); 289 TestThreadUtils.runOnUiThreadBlocking(() -> { 290 profile.removeBrowserPersistenceStorage(ids, (Boolean result) -> { 291 Assert.assertTrue(result); 292 helper.notifyCalled(); 293 }); 294 }); 295 helper.waitForCallback(callCount, 1); 296 callCount = helper.getCallCount(); 297 298 // Verify it was actually removed. 299 TestThreadUtils.runOnUiThreadBlocking(() -> { 300 profile.getBrowserPersistenceIds((Set<String> actualIds) -> { 301 Assert.assertTrue(actualIds.isEmpty()); 302 helper.notifyCalled(); 303 }); 304 }); 305 helper.waitForCallback(callCount, 1); 306 } 307 308 @Test 309 @SmallTest browserAndTabIsDestroyedWhenFragmentDestroyed()310 public void browserAndTabIsDestroyedWhenFragmentDestroyed() throws Throwable { 311 mActivityTestRule.launchShellWithUrl(mActivityTestRule.getTestDataURL("simple_page.html")); 312 313 CallbackHelper helper = new CallbackHelper(); 314 Browser browser = TestThreadUtils.runOnUiThreadBlocking( 315 () -> { return mActivityTestRule.getActivity().getBrowser(); }); 316 Tab tab = TestThreadUtils.runOnUiThreadBlocking(() -> { return browser.getActiveTab(); }); 317 TestThreadUtils.runOnUiThreadBlocking(() -> { 318 Assert.assertFalse(browser.isDestroyed()); 319 Assert.assertFalse(tab.isDestroyed()); 320 destroyFragment(helper); 321 }); 322 helper.waitForFirst(); 323 TestThreadUtils.runOnUiThreadBlocking(() -> { 324 Assert.assertTrue(browser.isDestroyed()); 325 Assert.assertTrue(tab.isDestroyed()); 326 }); 327 } 328 329 // Used to track new Browsers finish restoring. 330 private static final class BrowserRestoreHelper 331 implements InstrumentationActivity.OnCreatedCallback { 332 private final CallbackHelper mCallbackHelper; 333 public List<Browser> mBrowsers; 334 335 // |helper| is notified once restore is complete (or if a browser is created already 336 // restored). BrowserRestoreHelper(CallbackHelper helper)337 BrowserRestoreHelper(CallbackHelper helper) { 338 mCallbackHelper = helper; 339 mBrowsers = new ArrayList<Browser>(); 340 InstrumentationActivity.registerOnCreatedCallback(this); 341 } 342 343 @Override onCreated(Browser browser)344 public void onCreated(Browser browser) { 345 mBrowsers.add(browser); 346 if (!browser.isRestoringPreviousState()) { 347 mCallbackHelper.notifyCalled(); 348 return; 349 } 350 browser.registerBrowserRestoreCallback(new BrowserRestoreCallback() { 351 @Override 352 public void onRestoreCompleted() { 353 Assert.assertFalse(browser.isRestoringPreviousState()); 354 browser.unregisterBrowserRestoreCallback(this); 355 mCallbackHelper.notifyCalled(); 356 } 357 }); 358 } 359 } 360 @Test 361 @SmallTest 362 @MinWebLayerVersion(88) restoreUsingOnRestoreCompleted()363 public void restoreUsingOnRestoreCompleted() throws Throwable { 364 final String persistenceId = "x"; 365 Bundle extras = new Bundle(); 366 extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, persistenceId); 367 CallbackHelper callbackHelper = new CallbackHelper(); 368 BrowserRestoreHelper restoreHelper = new BrowserRestoreHelper(callbackHelper); 369 370 final String url = mActivityTestRule.getTestDataURL("simple_page.html"); 371 mActivityTestRule.launchShellWithUrl(url, extras); 372 // Wait for the restore to complete. 373 callbackHelper.waitForCallback(0, 1); 374 375 // Recreate and wait for restore. 376 mActivityTestRule.recreateActivity(); 377 callbackHelper.waitForCallback(1, 1); 378 } 379 getCurrentDisplayUri(Browser browser)380 private String getCurrentDisplayUri(Browser browser) { 381 NavigationController navigationController = 382 browser.getActiveTab().getNavigationController(); 383 return navigationController 384 .getNavigationEntryDisplayUri(navigationController.getNavigationListCurrentIndex()) 385 .toString(); 386 } 387 388 @Test 389 @SmallTest 390 @MinWebLayerVersion(87) twoFragmentsDifferentIncognitoProfiles()391 public void twoFragmentsDifferentIncognitoProfiles() throws Throwable { 392 // This test creates two browsers with different profile names and persistence ids. 393 final String persistenceId1 = "x"; 394 final String persistenceId2 = "y"; 395 Bundle extras = new Bundle(); 396 extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, persistenceId1); 397 extras.putString(InstrumentationActivity.EXTRA_PROFILE_NAME, persistenceId1); 398 extras.putBoolean(InstrumentationActivity.EXTRA_IS_INCOGNITO, true); 399 CallbackHelper callbackHelper = new CallbackHelper(); 400 BrowserRestoreHelper restoreHelper = new BrowserRestoreHelper(callbackHelper); 401 final String url1 = mActivityTestRule.getTestDataURL("simple_page.html"); 402 mActivityTestRule.launchShellWithUrl(url1, extras); 403 404 // Wait for the restore to complete. 405 int currentCallCount = 0; 406 callbackHelper.waitForCallback(currentCallCount++, 1); 407 408 // Create another fragment 409 Browser newBrowser = TestThreadUtils.runOnUiThreadBlocking(() -> { 410 InstrumentationActivity activity = mActivityTestRule.getActivity(); 411 Intent intent = new Intent(activity.getIntent()); 412 intent.putExtra(InstrumentationActivity.EXTRA_PERSISTENCE_ID, persistenceId2); 413 intent.putExtra(InstrumentationActivity.EXTRA_PROFILE_NAME, persistenceId2); 414 415 // The newly created browser should have a different Profile, but be incognito. 416 Browser browser = Browser.fromFragment( 417 activity.createBrowserFragment(android.R.id.content, intent)); 418 Assert.assertNotEquals(browser, activity.getBrowser()); 419 Assert.assertNotEquals(browser.getProfile(), activity.getBrowser().getProfile()); 420 Assert.assertTrue(activity.getBrowser().getProfile().isIncognito()); 421 Assert.assertTrue(browser.getProfile().isIncognito()); 422 return browser; 423 }); 424 425 // Wait for restore. 426 callbackHelper.waitForCallback(currentCallCount++, 1); 427 428 // Navigate to url2. 429 final String url2 = mActivityTestRule.getTestDataURL("simple_page2.html"); 430 Tab newTab = TestThreadUtils.runOnUiThreadBlocking(() -> newBrowser.getActiveTab()); 431 mActivityTestRule.navigateAndWait(newTab, url2, true); 432 433 Profile[] profiles = new Profile[2]; 434 TestThreadUtils.runOnUiThreadBlocking(() -> { 435 profiles[0] = mActivityTestRule.getActivity().getBrowser().getProfile(); 436 profiles[1] = newBrowser.getProfile(); 437 }); 438 439 // Recreate the activity and wait for two restores (for the two fragments). 440 InstrumentationActivity.sAllowMultipleFragments = true; 441 restoreHelper.mBrowsers.clear(); 442 mActivityTestRule.recreateActivity(); 443 callbackHelper.waitForCallback(currentCallCount++, 1); 444 callbackHelper.waitForCallback(currentCallCount++, 1); 445 446 TestThreadUtils.runOnUiThreadBlocking(() -> { 447 // Two new Browsers should be created, but have the profiles created earlier. 448 Assert.assertEquals(2, restoreHelper.mBrowsers.size()); 449 Browser restoredBrowser1 = restoreHelper.mBrowsers.get(0); 450 Browser restoredBrowser2 = restoreHelper.mBrowsers.get(1); 451 if (restoredBrowser2.getProfile().getName().equals(persistenceId1)) { 452 restoredBrowser1 = restoreHelper.mBrowsers.get(1); 453 restoredBrowser2 = restoreHelper.mBrowsers.get(0); 454 } 455 Assert.assertEquals(restoredBrowser1.getProfile().getName(), persistenceId1); 456 Assert.assertTrue(restoredBrowser1.getProfile().isIncognito()); 457 Assert.assertEquals(profiles[0], restoredBrowser1.getProfile()); 458 Assert.assertEquals(url1, getCurrentDisplayUri(restoredBrowser1)); 459 460 Assert.assertEquals(restoredBrowser2.getProfile().getName(), persistenceId2); 461 Assert.assertTrue(restoredBrowser2.getProfile().isIncognito()); 462 Assert.assertEquals(profiles[1], restoredBrowser2.getProfile()); 463 Assert.assertEquals(url2, getCurrentDisplayUri(restoredBrowser2)); 464 Assert.assertNotEquals(restoredBrowser2, newBrowser); 465 }); 466 } 467 468 @Test 469 @SmallTest 470 @MinWebLayerVersion(87) twoFragmentsSameIncognitoProfile()471 public void twoFragmentsSameIncognitoProfile() throws Throwable { 472 // This test creates two browsers with the same profile, but different persistence ids. 473 final String persistenceId1 = "x"; 474 final String persistenceId2 = "y"; 475 Bundle extras = new Bundle(); 476 extras.putString(InstrumentationActivity.EXTRA_PERSISTENCE_ID, persistenceId1); 477 extras.putString(InstrumentationActivity.EXTRA_PROFILE_NAME, persistenceId1); 478 extras.putBoolean(InstrumentationActivity.EXTRA_IS_INCOGNITO, true); 479 CallbackHelper callbackHelper = new CallbackHelper(); 480 BrowserRestoreHelper restoreHelper = new BrowserRestoreHelper(callbackHelper); 481 482 final String url1 = mActivityTestRule.getTestDataURL("simple_page.html"); 483 mActivityTestRule.launchShellWithUrl(url1, extras); 484 // Wait for the restore to complete. 485 int currentCallCount = 0; 486 callbackHelper.waitForCallback(currentCallCount++, 1); 487 488 // Create another fragment 489 Browser newBrowser = TestThreadUtils.runOnUiThreadBlocking(() -> { 490 InstrumentationActivity activity = mActivityTestRule.getActivity(); 491 Intent intent = new Intent(activity.getIntent()); 492 intent.putExtra(InstrumentationActivity.EXTRA_PERSISTENCE_ID, persistenceId2); 493 494 // The newly created browser should have a different Profile, but be incognito. 495 Browser browser = Browser.fromFragment( 496 activity.createBrowserFragment(android.R.id.content, intent)); 497 Assert.assertNotEquals(browser, activity.getBrowser()); 498 Assert.assertEquals(browser.getProfile(), activity.getBrowser().getProfile()); 499 Assert.assertTrue(activity.getBrowser().getProfile().isIncognito()); 500 return browser; 501 }); 502 Profile profile = TestThreadUtils.runOnUiThreadBlocking(() -> newBrowser.getProfile()); 503 // Wait for restore. 504 callbackHelper.waitForCallback(currentCallCount++, 1); 505 506 // Navigate to url2. 507 final String url2 = mActivityTestRule.getTestDataURL("simple_page2.html"); 508 Tab newTab = TestThreadUtils.runOnUiThreadBlocking(() -> newBrowser.getActiveTab()); 509 mActivityTestRule.navigateAndWait(newTab, url2, true); 510 511 // Recreate the activity and wait for two restores (for the two fragments). 512 InstrumentationActivity.sAllowMultipleFragments = true; 513 restoreHelper.mBrowsers.clear(); 514 mActivityTestRule.recreateActivity(); 515 callbackHelper.waitForCallback(currentCallCount++, 1); 516 callbackHelper.waitForCallback(currentCallCount++, 1); 517 518 TestThreadUtils.runOnUiThreadBlocking(() -> { 519 // Two new Browsers should be created. 520 Assert.assertEquals(2, restoreHelper.mBrowsers.size()); 521 Browser restoredBrowser1 = restoreHelper.mBrowsers.get(0); 522 Browser restoredBrowser2 = restoreHelper.mBrowsers.get(1); 523 Assert.assertEquals(profile, restoredBrowser1.getProfile()); 524 525 Assert.assertEquals(profile, restoredBrowser2.getProfile()); 526 Assert.assertNotEquals(restoredBrowser2, newBrowser); 527 528 if (getCurrentDisplayUri(restoredBrowser1).equals(url1)) { 529 Assert.assertEquals(url2, getCurrentDisplayUri(restoredBrowser2)); 530 } else { 531 Assert.assertEquals(url1, getCurrentDisplayUri(restoredBrowser2)); 532 Assert.assertEquals(url2, getCurrentDisplayUri(restoredBrowser1)); 533 } 534 }); 535 } 536 } 537