Commit af52bf4c authored by Peter Kasting's avatar Peter Kasting Committed by Commit Bot

Revert "Merge Webapk/TWA disclosure controller 1"

This reverts commit 6460aa02.

Reason for revert: Looks to have broken Android compile: https://ci.chromium.org/p/chromium/builders/ci/android-archive-rel/15768

Original change's description:
> Merge Webapk/TWA disclosure controller 1
>
> This CL moves WebappDisclosureSnackbarController to browserservices
> folder, makes it use TrustedWebActivityModel and the
> DisclosureInfobar as TrustedWebActivityDisclosureController.
>
> This will change the text in unbound webapk's disclosure snackbar text
> to be the same as TWA one.
>
> Bug: 1128675
> Change-Id: I900c41c04a6f36489bed1e08cf81c74f89e2801e
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2453896
> Reviewed-by: Andrew Grieve <agrieve@chromium.org>
> Reviewed-by: Peter Conn <peconn@chromium.org>
> Commit-Queue: Ella Ge <eirage@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#817516}

TBR=agrieve@chromium.org,peconn@chromium.org,eirage@chromium.org

Change-Id: I97a14528dbe701a19753b87b3a9a13963716099f
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 1128675
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2476775Reviewed-by: default avatarPeter Kasting <pkasting@chromium.org>
Commit-Queue: Peter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#817533}
parent 26204257
......@@ -218,7 +218,6 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TwaVerifier.java",
"java/src/org/chromium/chrome/browser/browserservices/ui/controller/webapps/AddToHomescreenVerifier.java",
"java/src/org/chromium/chrome/browser/browserservices/ui/controller/webapps/WebApkVerifier.java",
"java/src/org/chromium/chrome/browser/browserservices/ui/controller/webapps/WebappDisclosureController.java",
"java/src/org/chromium/chrome/browser/browserservices/ui/controller/webapps/WebappVerifier.java",
"java/src/org/chromium/chrome/browser/browserservices/ui/splashscreen/SplashController.java",
"java/src/org/chromium/chrome/browser/browserservices/ui/splashscreen/SplashDelegate.java",
......@@ -1680,6 +1679,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java",
"java/src/org/chromium/chrome/browser/webapps/WebappDeferredStartupWithStorageHandler.java",
"java/src/org/chromium/chrome/browser/webapps/WebappDirectoryManager.java",
"java/src/org/chromium/chrome/browser/webapps/WebappDisclosureSnackbarController.java",
"java/src/org/chromium/chrome/browser/webapps/WebappExtras.java",
"java/src/org/chromium/chrome/browser/webapps/WebappIcon.java",
"java/src/org/chromium/chrome/browser/webapps/WebappInfo.java",
......
......@@ -33,7 +33,6 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityDisclosureControllerTest.java",
"junit/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityOpenTimeRecorderTest.java",
"junit/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TwaVerifierTest.java",
"junit/src/org/chromium/chrome/browser/browserservices/ui/controller/webapps/WebappDisclosureControllerTest.java",
"junit/src/org/chromium/chrome/browser/browserservices/ui/trustedwebactivity/DisclosureAcceptanceBroadcastReceiverTest.java",
"junit/src/org/chromium/chrome/browser/browserservices/ui/trustedwebactivity/DisclosureUiPickerTest.java",
"junit/src/org/chromium/chrome/browser/browserservices/ui/trustedwebactivity/FilledLazy.java",
......@@ -251,6 +250,7 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java",
"junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java",
"junit/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java",
"junit/src/org/chromium/chrome/browser/webapps/WebappDisclosureSnackbarControllerTest.java",
"junit/src/org/chromium/chrome/browser/webapps/WebappInfoTest.java",
"junit/src/org/chromium/chrome/browser/webapps/WebappIntentUtilsTest.java",
"junit/src/org/chromium/chrome/browser/webapps/WebappLauncherActivityTest.java",
......
......@@ -413,7 +413,7 @@ specific_include_rules = {
"WebappDeferredStartupWithStorageHandler\.java": [
"+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
],
"WebappDisclosureController\.java": [
"WebappDisclosureSnackbarController\.java": [
"+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
],
"AddToHomescreenCoordinator\.java": [
......
......@@ -7,8 +7,6 @@ package org.chromium.chrome.browser.webapps;
import androidx.annotation.Nullable;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.browserservices.ui.controller.webapps.WebappDisclosureController;
import org.chromium.chrome.browser.browserservices.ui.view.trustedwebactivity.DisclosureInfobar;
import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.Destroyable;
......@@ -29,11 +27,11 @@ public class WebApkActivityCoordinator implements Destroyable {
@Inject
public WebApkActivityCoordinator(ChromeActivity<?> activity,
WebappDeferredStartupWithStorageHandler deferredStartupWithStorageHandler,
WebappDisclosureController disclosureController, DisclosureInfobar disclosureInfobar,
WebappDisclosureSnackbarController disclosureSnackbarController,
WebApkActivityLifecycleUmaTracker webApkActivityLifecycleUmaTracker,
ActivityLifecycleDispatcher lifecycleDispatcher,
Lazy<WebApkUpdateManager> webApkUpdateManager) {
// We don't need to do anything with |disclosureController|, |disclosureInfobar| and
// We don't need to do anything with |disclosureSnackbarController| and
// |webApkActivityLifecycleUmaTracker|. We just need to resolve
// them so that they start working.
......
......@@ -304,7 +304,7 @@ public class WebappDataStorage {
* Deletes the data for a web app by clearing all the information inside the SharedPreferences
* file. This does NOT delete the file itself but the file is left empty.
*/
public void delete() {
void delete() {
deletePendingUpdateRequestFile();
mPreferences.edit().clear().apply();
}
......@@ -455,7 +455,7 @@ public class WebappDataStorage {
* Returns whether to show the user a privacy disclosure (used for TWAs and unbound WebAPKs).
* This is not cleared until the user explicitly acknowledges it.
*/
public boolean shouldShowDisclosure() {
boolean shouldShowDisclosure() {
return mPreferences.getBoolean(KEY_SHOW_DISCLOSURE, false);
}
......@@ -464,7 +464,7 @@ public class WebappDataStorage {
* disclosure on every resume of the Webapp. This should be called when the user has
* acknowledged the disclosure.
*/
public void clearShowDisclosure() {
void clearShowDisclosure() {
mPreferences.edit().putBoolean(KEY_SHOW_DISCLOSURE, false).apply();
}
......@@ -473,7 +473,7 @@ public class WebappDataStorage {
* This is set the first time an app is opened without storage (either right after install or
* after Chrome's storage is cleared).
*/
public void setShowDisclosure() {
void setShowDisclosure() {
mPreferences.edit().putBoolean(KEY_SHOW_DISCLOSURE, true).apply();
}
......
......@@ -23,10 +23,7 @@ import javax.inject.Inject;
*/
@ActivityScope
public class WebappDeferredStartupWithStorageHandler {
/**
* Interface for deferred startup task callbacks.
*/
public interface Task {
interface Task {
/**
* Called to run task.
* @param storage Null if there is no {@link WebappDataStorage} registered for the webapp
......
......@@ -2,27 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.browserservices.ui.controller.webapps;
import static org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityModel.DISCLOSURE_EVENTS_CALLBACK;
import static org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityModel.DISCLOSURE_STATE;
import static org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityModel.DISCLOSURE_STATE_DISMISSED_BY_USER;
import static org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityModel.DISCLOSURE_STATE_SHOWN;
import static org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityModel.PACKAGE_NAME;
package org.chromium.chrome.browser.webapps;
import androidx.annotation.Nullable;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityModel;
import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
import org.chromium.chrome.browser.webapps.WebApkExtras;
import org.chromium.chrome.browser.webapps.WebappDataStorage;
import org.chromium.chrome.browser.webapps.WebappDeferredStartupWithStorageHandler;
import org.chromium.chrome.browser.webapps.WebappExtras;
import org.chromium.chrome.browser.webapps.WebappRegistry;
import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver;
import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.components.webapk.lib.common.WebApkConstants;
import javax.inject.Inject;
......@@ -37,24 +28,18 @@ import javax.inject.Inject;
* next time the app is opened if it hasn't been acknowledged.
*/
@ActivityScope
public class WebappDisclosureController
implements NativeInitObserver, TrustedWebActivityModel.DisclosureEventsCallback {
public class WebappDisclosureSnackbarController
implements SnackbarManager.SnackbarController, PauseResumeWithNativeObserver {
private final ChromeActivity mActivity;
private final BrowserServicesIntentDataProvider mIntentDataProvider;
private final TrustedWebActivityModel mModel;
@Inject
public WebappDisclosureController(ChromeActivity<?> activity,
BrowserServicesIntentDataProvider intentDataProvider, TrustedWebActivityModel model,
public WebappDisclosureSnackbarController(ChromeActivity<?> activity,
BrowserServicesIntentDataProvider intentDataProvider,
WebappDeferredStartupWithStorageHandler deferredStartupWithStorageHandler,
ActivityLifecycleDispatcher lifecycleDispatcher) {
mActivity = activity;
mIntentDataProvider = intentDataProvider;
mModel = model;
model.set(DISCLOSURE_EVENTS_CALLBACK, this);
WebApkExtras webApkExtras = mIntentDataProvider.getWebApkExtras();
if (webApkExtras != null && webApkExtras.webApkPackageName != null) {
model.set(PACKAGE_NAME, webApkExtras.webApkPackageName);
}
lifecycleDispatcher.register(this);
......@@ -77,7 +62,7 @@ public class WebappDisclosureController
}
@Override
public void onFinishNativeInitialization() {
public void onResumeWithNative() {
WebappExtras webappExtras = mIntentDataProvider.getWebappExtras();
WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(
mIntentDataProvider.getWebappExtras().id);
......@@ -87,18 +72,23 @@ public class WebappDisclosureController
}
@Override
public void onDisclosureAccepted() {
WebappExtras webappExtras = mIntentDataProvider.getWebappExtras();
WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(
mIntentDataProvider.getWebappExtras().id);
if (storage != null) {
storage.clearShowDisclosure();
public void onPauseWithNative() {}
/**
* @param actionData an instance of WebappInfo
*/
@Override
public void onAction(Object actionData) {
if (actionData instanceof WebappDataStorage) {
((WebappDataStorage) actionData).clearShowDisclosure();
}
mModel.set(DISCLOSURE_STATE, DISCLOSURE_STATE_DISMISSED_BY_USER);
}
/**
* Stub expected by SnackbarController.
*/
@Override
public void onDisclosureShown() {}
public void onDismissNoAction(Object actionData) {}
/**
* Shows the disclosure informing the user the Webapp is running in Chrome.
......@@ -111,8 +101,14 @@ public class WebappDisclosureController
// If forced we set the bit to show the disclosure. This persists to future instances.
if (force) storage.setShowDisclosure();
if (!isShowing() && shouldShowDisclosure(storage)) {
mModel.set(DISCLOSURE_STATE, DISCLOSURE_STATE_SHOWN);
if (shouldShowDisclosure(storage)) {
mActivity.getSnackbarManager().showSnackbar(
Snackbar.make(mActivity.getResources().getString(
R.string.app_running_in_chrome_disclosure),
this, Snackbar.TYPE_PERSISTENT,
Snackbar.UMA_WEBAPK_PRIVACY_DISCLOSURE)
.setAction(mActivity.getResources().getString(R.string.ok), storage)
.setSingleLine(false));
}
}
......@@ -133,8 +129,4 @@ public class WebappDisclosureController
&& !webApkExtras.webApkPackageName.startsWith(
WebApkConstants.WEBAPK_PACKAGE_PREFIX);
}
public boolean isShowing() {
return mModel.get(DISCLOSURE_STATE) == DISCLOSURE_STATE_SHOWN;
}
}
......@@ -18,7 +18,6 @@ import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.browserservices.ui.SharedActivityCoordinator;
import org.chromium.chrome.browser.browserservices.ui.controller.webapps.WebappDisclosureController;
import org.chromium.chrome.browser.customtabs.CustomTabOrientationController;
import org.chromium.chrome.browser.dependency_injection.ChromeActivityCommonsModule;
import org.chromium.chrome.browser.dependency_injection.ModuleOverridesRule;
......@@ -135,8 +134,8 @@ public class WebApkInitializationTest {
mTrackingActivityLifecycleDispatcher.getRegisteredObserverClassNames();
assertTrue(registeredObserverClassNames.contains(
WebappActionsNotificationManager.class.getName()));
assertTrue(
registeredObserverClassNames.contains(WebappDisclosureController.class.getName()));
assertTrue(registeredObserverClassNames.contains(
WebappDisclosureSnackbarController.class.getName()));
assertTrue(registeredObserverClassNames.contains(
WebApkActivityLifecycleUmaTracker.class.getName()));
assertTrue(
......
......@@ -2,20 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.browserservices.ui.controller.webapps;
package org.chromium.chrome.browser.webapps;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityModel.DISCLOSURE_EVENTS_CALLBACK;
import static org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityModel.DISCLOSURE_STATE;
import static org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityModel.DISCLOSURE_STATE_DISMISSED_BY_USER;
import static org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityModel.DISCLOSURE_STATE_NOT_SHOWN;
import static org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityModel.DISCLOSURE_STATE_SHOWN;
import android.content.res.Resources;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
......@@ -28,45 +27,41 @@ import org.chromium.base.task.PostTask;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityModel;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.webapps.WebappActivity;
import org.chromium.chrome.browser.webapps.WebappDataStorage;
import org.chromium.chrome.browser.webapps.WebappDeferredStartupWithStorageHandler;
import org.chromium.chrome.browser.webapps.WebappIntentUtils;
import org.chromium.chrome.browser.webapps.WebappRegistry;
import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.chrome.test.util.browser.webapps.WebApkIntentDataProviderBuilder;
import org.chromium.components.webapk.lib.common.WebApkConstants;
/**
* Tests for WebappDisclosureController
* Tests for WebappDisclosureSnackbarController
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class WebappDisclosureControllerTest {
public class WebappDisclosureSnackbarControllerTest {
@Mock
public WebappActivity mActivity;
public TrustedWebActivityModel mModel;
@Mock
public SnackbarManager mManager;
@Mock
public Resources mResources;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
// Run AsyncTasks synchronously.
PostTask.setPrenativeThreadPoolExecutorForTesting(new RoboExecutorService());
}
@After
public void tearDown() {
PostTask.resetPrenativeThreadPoolExecutorForTesting();
doReturn("test text").when(mResources).getString(anyInt());
doReturn(mManager).when(mActivity).getSnackbarManager();
doReturn(mResources).when(mActivity).getResources();
}
private WebappDisclosureController buildControllerForWebApk(String webApkPackageName) {
private WebappDisclosureSnackbarController buildControllerForWebApk(String webApkPackageName) {
BrowserServicesIntentDataProvider intentDataProvider =
new WebApkIntentDataProviderBuilder(webApkPackageName, "https://pwa.rocks/")
.build();
mModel = new TrustedWebActivityModel();
return new WebappDisclosureController(mActivity, intentDataProvider, mModel,
return new WebappDisclosureSnackbarController(mActivity, intentDataProvider,
mock(WebappDeferredStartupWithStorageHandler.class),
mock(ActivityLifecycleDispatcher.class));
}
......@@ -78,80 +73,57 @@ public class WebappDisclosureControllerTest {
}
public void verifyShownThenDismissedOnNewCreateStorage(String packageName) {
WebappDisclosureController controller = buildControllerForWebApk(packageName);
WebappDisclosureSnackbarController controller = buildControllerForWebApk(packageName);
WebappDataStorage storage = registerStorageForWebApk(packageName);
// Simulates the case that shows the disclosure when creating a new storage.
controller.onDeferredStartupWithStorage(storage, true /* didCreateStorage */);
verify(mManager, times(1)).showSnackbar(any(Snackbar.class));
assertTrue(storage.shouldShowDisclosure());
assertSnackbarShown();
// Dismiss the disclosure.
mModel.get(DISCLOSURE_EVENTS_CALLBACK).onDisclosureAccepted();
assertSnackbarAccepted();
assertFalse(storage.shouldShowDisclosure());
storage.delete();
}
public void verifyShownThenDismissedOnRestart(String packageName) {
WebappDisclosureController controller = buildControllerForWebApk(packageName);
WebappDataStorage storage = registerStorageForWebApk(packageName);
// Simulates the case that shows the disclosure when finish native initialization.
storage.setShowDisclosure();
controller.onFinishNativeInitialization();
assertSnackbarShown();
// Simulate a restart or a resume.
controller.onResumeWithNative();
verify(mManager, times(2)).showSnackbar(any(Snackbar.class));
assertTrue(storage.shouldShowDisclosure());
// Dismiss the disclosure.
mModel.get(DISCLOSURE_EVENTS_CALLBACK).onDisclosureAccepted();
controller.onAction(storage);
assertSnackbarAccepted();
// Simulate resuming or starting again this time no disclosure should show.
assertFalse(storage.shouldShowDisclosure());
controller.onResumeWithNative();
verify(mManager, times(2)).showSnackbar(any(Snackbar.class));
storage.delete();
}
public void verifyNotShownOnExistingStorageWithoutShouldShowDisclosure(String packageName) {
WebappDisclosureController controller = buildControllerForWebApk(packageName);
WebappDisclosureSnackbarController controller = buildControllerForWebApk(packageName);
WebappDataStorage storage = registerStorageForWebApk(packageName);
// Simulate that starting with existing storage will not cause the disclosure to show.
assertFalse(storage.shouldShowDisclosure());
controller.onDeferredStartupWithStorage(storage, false /* didCreateStorage */);
assertSnackbarNotShown();
verify(mManager, times(0)).showSnackbar(any(Snackbar.class));
storage.delete();
}
public void verifyNeverShown(String packageName) {
WebappDisclosureController controller = buildControllerForWebApk(packageName);
WebappDisclosureSnackbarController controller = buildControllerForWebApk(packageName);
WebappDataStorage storage = registerStorageForWebApk(packageName);
// Try to show the disclosure the first time.
controller.onDeferredStartupWithStorage(storage, true /* didCreateStorage */);
assertSnackbarNotShown();
verify(mManager, times(0)).showSnackbar(any(Snackbar.class));
// Try to the disclosure again this time emulating a restart.
controller.onFinishNativeInitialization();
assertSnackbarNotShown();
// Try to the disclosure again this time emulating a restart or a resume.
controller.onResumeWithNative();
verify(mManager, times(0)).showSnackbar(any(Snackbar.class));
storage.delete();
}
private void assertSnackbarShown() {
assertEquals(DISCLOSURE_STATE_SHOWN, mModel.get(DISCLOSURE_STATE));
}
private void assertSnackbarAccepted() {
assertEquals(DISCLOSURE_STATE_DISMISSED_BY_USER, mModel.get(DISCLOSURE_STATE));
}
private void assertSnackbarNotShown() {
assertEquals(DISCLOSURE_STATE_NOT_SHOWN, mModel.get(DISCLOSURE_STATE));
}
@Test
@Feature({"Webapps"})
public void testUnboundWebApkShowDisclosure() {
......@@ -159,13 +131,6 @@ public class WebappDisclosureControllerTest {
verifyShownThenDismissedOnNewCreateStorage(packageName);
}
@Test
@Feature({"Webapps"})
public void testUnboundWebApkShowDisclosure2() {
String packageName = "unbound";
verifyShownThenDismissedOnRestart(packageName);
}
@Test
@Feature({"Webapps"})
public void testUnboundWebApkNoDisclosureOnExistingStorage() {
......
......@@ -3508,6 +3508,9 @@ Data from your Incognito session will only be cleared from Chrome when you <ph n
</message>
<!-- WebAPK/TWA related strings -->
<message name="IDS_APP_RUNNING_IN_CHROME_DISCLOSURE" desc="Message on the snackbar that indicates an app may use Chrome data.">
This app is running in Chrome
</message>
<message name="IDS_TWA_RUNNING_IN_CHROME" desc="Message on a snackbar indicating that the current Activity may use Chrome data (the rest of the app may not be).">
Running in Chrome
</message>
......
c148a3b6564ccb24297b4fbd58ba2ad983a11985
\ No newline at end of file
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