// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.content.browser;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Criteria;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.CriteriaNotSatisfiedException;
import org.chromium.base.test.util.Feature;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer;
import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper;
import org.chromium.content_shell_apk.ContentShellActivityTestRule;
import org.chromium.device.geolocation.LocationProviderOverrider;
import org.chromium.device.geolocation.MockLocationProvider;
/**
* Test suite for ensureing that Geolocation interacts as expected
* with ContentView APIs - e.g. that it's started and stopped as the
* ContentView is hidden or shown.
*/
@RunWith(BaseJUnit4ClassRunner.class)
public class ContentViewLocationTest {
@Rule
public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
private TestCallbackHelperContainer mTestCallbackHelperContainer;
private TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper mJavascriptHelper;
private MockLocationProvider mMockLocationProvider;
private void hideContentViewOnUiThread() {
InstrumentationRegistry.getInstrumentation()
.runOnMainSync(
new Runnable() {
@Override
public void run() {
mActivityTestRule.getWebContents().onHide();
}
});
}
private void showContentViewOnUiThread() {
InstrumentationRegistry.getInstrumentation()
.runOnMainSync(
new Runnable() {
@Override
public void run() {
mActivityTestRule.getWebContents().onShow();
}
});
}
private void pollForPositionCallback() throws Throwable {
mJavascriptHelper.evaluateJavaScriptForTests(
mActivityTestRule.getWebContents(), "positionCount = 0");
mJavascriptHelper.waitUntilHasValue();
Assert.assertEquals(0, Integer.parseInt(mJavascriptHelper.getJsonResultAndClear()));
CriteriaHelper.pollInstrumentationThread(
() -> {
mJavascriptHelper.evaluateJavaScriptForTests(
mActivityTestRule.getWebContents(), "positionCount");
try {
mJavascriptHelper.waitUntilHasValue();
} catch (Exception e) {
throw new CriteriaNotSatisfiedException(e);
}
int result = Integer.parseInt(mJavascriptHelper.getJsonResultAndClear());
Criteria.checkThat(result, Matchers.greaterThan(0));
});
}
private void startGeolocationWatchPosition() throws Throwable {
mJavascriptHelper.evaluateJavaScriptForTests(
mActivityTestRule.getWebContents(), "initiate_watchPosition();");
mJavascriptHelper.waitUntilHasValue();
}
private void ensureGeolocationRunning(final boolean running) {
CriteriaHelper.pollInstrumentationThread(
() -> {
Criteria.checkThat(mMockLocationProvider.isRunning(), Matchers.is(running));
});
}
@Before
public void setUp() {
mMockLocationProvider = new MockLocationProvider();
LocationProviderOverrider.setLocationProviderImpl(mMockLocationProvider);
try {
mActivityTestRule.launchContentShellWithUrlSync(
"content/test/data/android/geolocation.html");
} catch (Throwable t) {
Assert.fail();
}
mTestCallbackHelperContainer =
new TestCallbackHelperContainer(mActivityTestRule.getWebContents());
mJavascriptHelper = new OnEvaluateJavaScriptResultHelper();
ensureGeolocationRunning(false);
}
@After
public void tearDown() {
mMockLocationProvider.stopUpdates();
}
@Test
@MediumTest
@Feature({"Location"})
public void testWatchHideShowStop() throws Throwable {
startGeolocationWatchPosition();
pollForPositionCallback();
ensureGeolocationRunning(true);
// Now hide the ContentView and ensure that geolocation stops.
hideContentViewOnUiThread();
ensureGeolocationRunning(false);
mJavascriptHelper.evaluateJavaScriptForTests(
mActivityTestRule.getWebContents(), "positionCount = 0");
mJavascriptHelper.waitUntilHasValue();
// Show the ContentView again and ensure that geolocation starts again.
showContentViewOnUiThread();
pollForPositionCallback();
ensureGeolocationRunning(true);
// Navigate away and ensure that geolocation stops.
mActivityTestRule.loadUrl(
mActivityTestRule.getWebContents().getNavigationController(),
mTestCallbackHelperContainer,
new LoadUrlParams("about:blank"));
ensureGeolocationRunning(false);
}
@Test
@MediumTest
@Feature({"Location"})
public void testHideWatchResume() throws Throwable {
hideContentViewOnUiThread();
startGeolocationWatchPosition();
ensureGeolocationRunning(false);
showContentViewOnUiThread();
pollForPositionCallback();
ensureGeolocationRunning(true);
}
@Test
@MediumTest
@Feature({"Location"})
public void testWatchHideNewWatchShow() throws Throwable {
startGeolocationWatchPosition();
pollForPositionCallback();
ensureGeolocationRunning(true);
hideContentViewOnUiThread();
// Make sure that when starting a new watch while paused we still don't
// start up geolocation until we show the content view again.
startGeolocationWatchPosition();
ensureGeolocationRunning(false);
showContentViewOnUiThread();
pollForPositionCallback();
ensureGeolocationRunning(true);
}
@Test
@MediumTest
@Feature({"Location"})
public void testHideWatchStopShow() throws Throwable {
hideContentViewOnUiThread();
startGeolocationWatchPosition();
ensureGeolocationRunning(false);
mActivityTestRule.loadUrl(
mActivityTestRule.getWebContents().getNavigationController(),
mTestCallbackHelperContainer,
new LoadUrlParams("about:blank"));
showContentViewOnUiThread();
ensureGeolocationRunning(false);
}
}