Commit 2b3f166f authored by Peter E Conn's avatar Peter E Conn Committed by Commit Bot

🤝 Create "Running in Chrome" notification.

Creates the various strings and constants required for the "Running in
Chrome" notification. The logic to trigger the notification when
appropriate, along with tests and the ability to act on the user
pressing on the notification, will be coming in following CLs.

Bug: 1068106
Change-Id: I5788a072e87768e55568e4b2a593554b51067d49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2159467
Commit-Queue: Peter Conn <peconn@chromium.org>
Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#763299}
parent 5039a87b
...@@ -197,6 +197,7 @@ chrome_java_sources = [ ...@@ -197,6 +197,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/sharing/TwaSharingController.java", "java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/sharing/TwaSharingController.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/SplashImageHolder.java", "java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/SplashImageHolder.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/TwaSplashController.java", "java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/TwaSplashController.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/view/DisclosureNotification.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/view/NewDisclosureSnackbar.java", "java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/view/NewDisclosureSnackbar.java",
"java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/view/TrustedWebActivityDisclosureView.java", "java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/view/TrustedWebActivityDisclosureView.java",
"java/src/org/chromium/chrome/browser/browsing_data/BrowsingDataBridge.java", "java/src/org/chromium/chrome/browser/browsing_data/BrowsingDataBridge.java",
......
...@@ -19,6 +19,7 @@ import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controll ...@@ -19,6 +19,7 @@ import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controll
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.TwaRegistrar; import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.TwaRegistrar;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.Verifier; import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.Verifier;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.splashscreen.TwaSplashController; import org.chromium.chrome.browser.browserservices.trustedwebactivityui.splashscreen.TwaSplashController;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.view.DisclosureNotification;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.view.NewDisclosureSnackbar; import org.chromium.chrome.browser.browserservices.trustedwebactivityui.view.NewDisclosureSnackbar;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.view.TrustedWebActivityDisclosureView; import org.chromium.chrome.browser.browserservices.trustedwebactivityui.view.TrustedWebActivityDisclosureView;
import org.chromium.chrome.browser.customtabs.CustomTabStatusBarColorProvider; import org.chromium.chrome.browser.customtabs.CustomTabStatusBarColorProvider;
...@@ -46,6 +47,7 @@ import dagger.Lazy; ...@@ -46,6 +47,7 @@ import dagger.Lazy;
public class TrustedWebActivityCoordinator implements InflationObserver, NativeInitObserver { public class TrustedWebActivityCoordinator implements InflationObserver, NativeInitObserver {
private final Lazy<TrustedWebActivityDisclosureView> mDisclosureView; private final Lazy<TrustedWebActivityDisclosureView> mDisclosureView;
private final Lazy<NewDisclosureSnackbar> mNewDisclosureView; private final Lazy<NewDisclosureSnackbar> mNewDisclosureView;
private final Lazy<DisclosureNotification> mDisclosureNotification;
private final CurrentPageVerifier mCurrentPageVerifier; private final CurrentPageVerifier mCurrentPageVerifier;
private TrustedWebActivityBrowserControlsVisibilityManager mBrowserControlsVisibilityManager; private TrustedWebActivityBrowserControlsVisibilityManager mBrowserControlsVisibilityManager;
private final CustomTabToolbarColorController mToolbarColorController; private final CustomTabToolbarColorController mToolbarColorController;
...@@ -64,6 +66,7 @@ public class TrustedWebActivityCoordinator implements InflationObserver, NativeI ...@@ -64,6 +66,7 @@ public class TrustedWebActivityCoordinator implements InflationObserver, NativeI
TrustedWebActivityDisclosureController disclosureController, TrustedWebActivityDisclosureController disclosureController,
Lazy<TrustedWebActivityDisclosureView> disclosureView, Lazy<TrustedWebActivityDisclosureView> disclosureView,
Lazy<NewDisclosureSnackbar> newDisclosureView, Lazy<NewDisclosureSnackbar> newDisclosureView,
Lazy<DisclosureNotification> disclosureNotification,
TrustedWebActivityOpenTimeRecorder openTimeRecorder, TrustedWebActivityOpenTimeRecorder openTimeRecorder,
CurrentPageVerifier currentPageVerifier, CurrentPageVerifier currentPageVerifier,
Verifier verifier, Verifier verifier,
...@@ -84,6 +87,7 @@ public class TrustedWebActivityCoordinator implements InflationObserver, NativeI ...@@ -84,6 +87,7 @@ public class TrustedWebActivityCoordinator implements InflationObserver, NativeI
// so they start working. // so they start working.
mDisclosureView = disclosureView; mDisclosureView = disclosureView;
mNewDisclosureView = newDisclosureView; mNewDisclosureView = newDisclosureView;
mDisclosureNotification = disclosureNotification;
mCurrentPageVerifier = currentPageVerifier; mCurrentPageVerifier = currentPageVerifier;
mBrowserControlsVisibilityManager = browserControlsVisibilityManager; mBrowserControlsVisibilityManager = browserControlsVisibilityManager;
mToolbarColorController = toolbarColorController; mToolbarColorController = toolbarColorController;
...@@ -106,6 +110,20 @@ public class TrustedWebActivityCoordinator implements InflationObserver, NativeI ...@@ -106,6 +110,20 @@ public class TrustedWebActivityCoordinator implements InflationObserver, NativeI
new PostMessageDisabler(customTabsConnection, intentDataProvider)); new PostMessageDisabler(customTabsConnection, intentDataProvider));
} }
private void initDisclosure(Lazy<TrustedWebActivityDisclosureView> disclosureView,
Lazy<NewDisclosureSnackbar> newDisclosureView,
Lazy<DisclosureNotification> disclosureNotification) {
// Calling get on the appropriate Lazy instance will cause Dagger to create the class.
// The classes wire themselves up to the rest of the code in their constructors.
if (ChromeFeatureList.isEnabled(ChromeFeatureList.TRUSTED_WEB_ACTIVITY_NEW_DISCLOSURE)) {
// TODO(https://crbug.com/1068106): Determine whether notifications (both in general and
// the two channels we care about) are enabled. If so call disclosureNotification.get().
newDisclosureView.get().showIfNeeded();
} else {
disclosureView.get().showIfNeeded();
}
}
@Override @Override
public void onPreInflationStartup() { public void onPreInflationStartup() {
if (mCurrentPageVerifier.getState() == null) { if (mCurrentPageVerifier.getState() == null) {
...@@ -124,13 +142,7 @@ public class TrustedWebActivityCoordinator implements InflationObserver, NativeI ...@@ -124,13 +142,7 @@ public class TrustedWebActivityCoordinator implements InflationObserver, NativeI
@Override @Override
public void onFinishNativeInitialization() { public void onFinishNativeInitialization() {
// Calling get on the appropriate Lazy instance will cause Dagger to create the class. initDisclosure(mDisclosureView, mNewDisclosureView, mDisclosureNotification);
// The classes wire themselves up to the rest of the code in their constructors.
if (ChromeFeatureList.isEnabled(ChromeFeatureList.TRUSTED_WEB_ACTIVITY_NEW_DISCLOSURE)) {
mNewDisclosureView.get().showIfNeeded();
} else {
mDisclosureView.get().showIfNeeded();
}
} }
private void initSplashScreen(Lazy<TwaSplashController> splashController, private void initSplashScreen(Lazy<TwaSplashController> splashController,
......
// 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.
package org.chromium.chrome.browser.browserservices.trustedwebactivityui.view;
import static org.chromium.chrome.browser.browserservices.trustedwebactivityui.TrustedWebActivityModel.DISCLOSURE_SCOPE;
import static org.chromium.chrome.browser.browserservices.trustedwebactivityui.TrustedWebActivityModel.DISCLOSURE_STATE;
import static org.chromium.chrome.browser.browserservices.trustedwebactivityui.TrustedWebActivityModel.DISCLOSURE_STATE_NOT_SHOWN;
import static org.chromium.chrome.browser.browserservices.trustedwebactivityui.TrustedWebActivityModel.DISCLOSURE_STATE_SHOWN;
import static org.chromium.chrome.browser.dependency_injection.ChromeCommonQualifiers.APP_CONTEXT;
import static org.chromium.chrome.browser.notifications.NotificationConstants.NOTIFICATION_ID_TWA_DISCLOSURE;
import android.content.Context;
import android.content.res.Resources;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.TrustedWebActivityModel;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.StartStopWithNativeObserver;
import org.chromium.chrome.browser.notifications.NotificationBuilderFactory;
import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
import org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions;
import org.chromium.components.browser_ui.notifications.ChromeNotification;
import org.chromium.components.browser_ui.notifications.NotificationManagerProxy;
import org.chromium.components.browser_ui.notifications.NotificationManagerProxyImpl;
import org.chromium.components.browser_ui.notifications.NotificationMetadata;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyObservable;
import javax.inject.Inject;
import javax.inject.Named;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
/**
* Displays a notification when the user is on the verified domain. The first such notification (per
* TWA) is urgent priority, subsequent ones are low priority.
*/
public class DisclosureNotification implements
PropertyObservable.PropertyObserver<PropertyKey>, StartStopWithNativeObserver {
private final Context mContext;
private final Resources mResources;
private final TrustedWebActivityModel mModel;
private final NotificationManagerProxy mNotificationManager;
private String mCurrentScope;
@Inject
DisclosureNotification(
@Named(APP_CONTEXT) Context context,
Resources resources,
TrustedWebActivityModel model,
ActivityLifecycleDispatcher lifecycleDispatcher) {
mContext = context;
mResources = resources;
mNotificationManager = new NotificationManagerProxyImpl(mContext);
mModel = model;
mModel.addObserver(this);
lifecycleDispatcher.register(this);
}
private void show() {
String mCurrentScope = mModel.get(DISCLOSURE_SCOPE);
// TODO(https://crbug.com/1068106): Determine whether this is the first display.
ChromeNotification notification = createNotification(true, mCurrentScope);
mNotificationManager.notify(notification);
}
private void dismiss() {
mNotificationManager.cancel(mCurrentScope, NOTIFICATION_ID_TWA_DISCLOSURE);
mCurrentScope = null;
}
private ChromeNotification createNotification(boolean firstTime, String scope) {
int umaType;
int preOPriority;
String channelId;
if (firstTime) {
umaType = NotificationUmaTracker.SystemNotificationType.TWA_DISCLOSURE_INITIAL;
preOPriority = NotificationCompat.PRIORITY_MAX;
channelId = ChromeChannelDefinitions.ChannelId.TWA_DISCLOSURE_INITIAL;
} else {
umaType = NotificationUmaTracker.SystemNotificationType.TWA_DISCLOSURE_SUBSEQUENT;
preOPriority = NotificationCompat.PRIORITY_MIN;
channelId = ChromeChannelDefinitions.ChannelId.TWA_DISCLOSURE_SUBSEQUENT;
}
// We use the TWA's package name as the notification tag so that multiple different TWAs
// don't interfere with each other.
NotificationMetadata metadata =
new NotificationMetadata(umaType, scope, NOTIFICATION_ID_TWA_DISCLOSURE);
String title = mResources.getString(R.string.twa_running_in_chrome);
String text = mResources.getString(R.string.twa_running_in_chrome_v2, scope);
boolean preferCompat = true;
// The notification is being displayed by Chrome, so we don't need to provide a
// remoteAppPackageName.
String remoteAppPackageName = null;
// TODO(https://crbug.com/1068106): Add intent for tapping on the content.
// TODO(https://crbug.com/1068106): Add actions.
return NotificationBuilderFactory
.createChromeNotificationBuilder(
preferCompat, channelId, remoteAppPackageName, metadata)
.setSmallIcon(R.drawable.ic_chrome)
.setContentTitle(title)
.setContentText(text)
.setShowWhen(false)
.setAutoCancel(false)
.setOngoing(!firstTime)
.setPriorityBeforeO(preOPriority)
.buildChromeNotification();
}
@Override
public void onPropertyChanged(PropertyObservable<PropertyKey> source,
@Nullable PropertyKey propertyKey) {
if (propertyKey != DISCLOSURE_STATE) return;
switch (mModel.get(DISCLOSURE_STATE)) {
case DISCLOSURE_STATE_SHOWN:
show();
break;
case DISCLOSURE_STATE_NOT_SHOWN:
dismiss();
break;
}
}
@Override
public void onStartWithNative() {
if (mModel.get(DISCLOSURE_STATE) == DISCLOSURE_STATE_SHOWN) show();
}
@Override
public void onStopWithNative() {
dismiss();
}
}
...@@ -115,6 +115,12 @@ public class NotificationConstants { ...@@ -115,6 +115,12 @@ public class NotificationConstants {
*/ */
public static final int NOTIFICATION_ID_CLICK_TO_CALL_ERROR = 12; public static final int NOTIFICATION_ID_CLICK_TO_CALL_ERROR = 12;
/**
* Unique identifier for the high priority "Running in Chrome" notification displayed when a
* TWA is run. It will be high priority the first time and low priority subsequently.
*/
public static final int NOTIFICATION_ID_TWA_DISCLOSURE = 13;
/** /**
* Separator used to separate the notification origin from additional data such as the * Separator used to separate the notification origin from additional data such as the
* developer specified tag. This and the prefix following it need to be the same as the one * developer specified tag. This and the prefix following it need to be the same as the one
......
...@@ -53,7 +53,8 @@ public class NotificationUmaTracker { ...@@ -53,7 +53,8 @@ public class NotificationUmaTracker {
SystemNotificationType.CLICK_TO_CALL, SystemNotificationType.SHARED_CLIPBOARD, SystemNotificationType.CLICK_TO_CALL, SystemNotificationType.SHARED_CLIPBOARD,
SystemNotificationType.PERMISSION_REQUESTS, SystemNotificationType.PERMISSION_REQUESTS,
SystemNotificationType.PERMISSION_REQUESTS_HIGH, SystemNotificationType.ANNOUNCEMENT, SystemNotificationType.PERMISSION_REQUESTS_HIGH, SystemNotificationType.ANNOUNCEMENT,
SystemNotificationType.SHARE_SAVE_IMAGE}) SystemNotificationType.SHARE_SAVE_IMAGE, SystemNotificationType.TWA_DISCLOSURE_INITIAL,
SystemNotificationType.TWA_DISCLOSURE_SUBSEQUENT})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface SystemNotificationType { public @interface SystemNotificationType {
int UNKNOWN = -1; int UNKNOWN = -1;
...@@ -80,8 +81,10 @@ public class NotificationUmaTracker { ...@@ -80,8 +81,10 @@ public class NotificationUmaTracker {
int PERMISSION_REQUESTS_HIGH = 20; int PERMISSION_REQUESTS_HIGH = 20;
int ANNOUNCEMENT = 21; int ANNOUNCEMENT = 21;
int SHARE_SAVE_IMAGE = 22; int SHARE_SAVE_IMAGE = 22;
int TWA_DISCLOSURE_INITIAL = 23;
int TWA_DISCLOSURE_SUBSEQUENT = 24;
int NUM_ENTRIES = 23; int NUM_ENTRIES = 25;
} }
/* /*
......
...@@ -68,7 +68,8 @@ public class ChromeChannelDefinitions extends ChannelDefinitions { ...@@ -68,7 +68,8 @@ public class ChromeChannelDefinitions extends ChannelDefinitions {
ChannelId.SCREEN_CAPTURE, ChannelId.CONTENT_SUGGESTIONS, ChannelId.WEBAPP_ACTIONS, ChannelId.SCREEN_CAPTURE, ChannelId.CONTENT_SUGGESTIONS, ChannelId.WEBAPP_ACTIONS,
ChannelId.SITES, ChannelId.SHARING, ChannelId.UPDATES, ChannelId.COMPLETED_DOWNLOADS, ChannelId.SITES, ChannelId.SHARING, ChannelId.UPDATES, ChannelId.COMPLETED_DOWNLOADS,
ChannelId.PERMISSION_REQUESTS, ChannelId.PERMISSION_REQUESTS_HIGH, ChannelId.PERMISSION_REQUESTS, ChannelId.PERMISSION_REQUESTS_HIGH,
ChannelId.ANNOUNCEMENT}) ChannelId.ANNOUNCEMENT, ChannelId.TWA_DISCLOSURE_INITIAL,
ChannelId.TWA_DISCLOSURE_SUBSEQUENT})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface ChannelId { public @interface ChannelId {
String BROWSER = "browser"; String BROWSER = "browser";
...@@ -87,6 +88,8 @@ public class ChromeChannelDefinitions extends ChannelDefinitions { ...@@ -87,6 +88,8 @@ public class ChromeChannelDefinitions extends ChannelDefinitions {
String PERMISSION_REQUESTS = "permission_requests"; String PERMISSION_REQUESTS = "permission_requests";
String PERMISSION_REQUESTS_HIGH = "permission_requests_high"; String PERMISSION_REQUESTS_HIGH = "permission_requests_high";
String ANNOUNCEMENT = "announcement"; String ANNOUNCEMENT = "announcement";
String TWA_DISCLOSURE_INITIAL = "twa_disclosure_initial";
String TWA_DISCLOSURE_SUBSEQUENT = "twa_disclosure_subsequent";
} }
@StringDef({ChannelGroupId.GENERAL, ChannelGroupId.SITES}) @StringDef({ChannelGroupId.GENERAL, ChannelGroupId.SITES})
...@@ -195,6 +198,16 @@ public class ChromeChannelDefinitions extends ChannelDefinitions { ...@@ -195,6 +198,16 @@ public class ChromeChannelDefinitions extends ChannelDefinitions {
NotificationManager.IMPORTANCE_LOW, ChannelGroupId.GENERAL, NotificationManager.IMPORTANCE_LOW, ChannelGroupId.GENERAL,
true /* showNotificationBadges */)); true /* showNotificationBadges */));
// Not added to startup channels as not all users will use Trusted Web Activities.
map.put(ChannelId.TWA_DISCLOSURE_INITIAL,
new PredefinedChannel(ChannelId.TWA_DISCLOSURE_INITIAL,
R.string.twa_running_in_chrome_channel_name_initial,
NotificationManager.IMPORTANCE_MAX, ChannelGroupId.GENERAL));
map.put(ChannelId.TWA_DISCLOSURE_SUBSEQUENT,
new PredefinedChannel(ChannelId.TWA_DISCLOSURE_SUBSEQUENT,
R.string.twa_running_in_chrome_channel_name_subsequent,
NotificationManager.IMPORTANCE_MIN, ChannelGroupId.GENERAL));
MAP = Collections.unmodifiableMap(map); MAP = Collections.unmodifiableMap(map);
STARTUP = Collections.unmodifiableSet(startup); STARTUP = Collections.unmodifiableSet(startup);
} }
......
...@@ -3045,6 +3045,12 @@ To change this setting, <ph name="BEGIN_LINK">&lt;resetlink&gt;</ph>reset sync<p ...@@ -3045,6 +3045,12 @@ To change this setting, <ph name="BEGIN_LINK">&lt;resetlink&gt;</ph>reset sync<p
<message name="IDS_TWA_RUNNING_IN_CHROME_V2" desc="Updated message on a snackbar indicating that the current Activity may use Chrome data (the rest of the app may not be)."> <message name="IDS_TWA_RUNNING_IN_CHROME_V2" desc="Updated message on a snackbar indicating that the current Activity may use Chrome data (the rest of the app may not be).">
History is shared with Chrome. Preferences are shared with <ph name="SITE_NAME">%1$s<ex>www.youtube.com</ex></ph>. History is shared with Chrome. Preferences are shared with <ph name="SITE_NAME">%1$s<ex>www.youtube.com</ex></ph>.
</message> </message>
<message name="IDS_TWA_RUNNING_IN_CHROME_CHANNEL_NAME_INITIAL" desc="Notification channel name for the initial, urgent priority notification telling the user a TWA is running in Chrome.">
Running in Chrome (Initial)
</message>
<message name="IDS_TWA_RUNNING_IN_CHROME_CHANNEL_NAME_SUBSEQUENT" desc="Notification channel name for follow up notifications telling the user a TWA is running in Chrome.">
Running in Chrome
</message>
<message name="IDS_TWA_CLEAR_DATA_DIALOG_TITLE" desc="Title of the clear data dialog showing after user uninstalls or clears data of an app hosting a Trusted Web Activity"> <message name="IDS_TWA_CLEAR_DATA_DIALOG_TITLE" desc="Title of the clear data dialog showing after user uninstalls or clears data of an app hosting a Trusted Web Activity">
<ph name="APP_NAME">%1$s<ex>YouTube</ex></ph> also has data in Chrome <ph name="APP_NAME">%1$s<ex>YouTube</ex></ph> also has data in Chrome
</message> </message>
......
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