blob: d70729d617c990a0b6ddbcf2f7e8b4c5117e1e40 [file] [log] [blame]
// Copyright 2013 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.contextmenu;
import android.content.Context;
import android.net.MailTo;
import android.text.TextUtils;
import android.util.Pair;
import android.view.ContextMenu;
import android.webkit.MimeTypeMap;
import android.webkit.URLUtil;
import androidx.annotation.IntDef;
import org.chromium.base.library_loader.LibraryProcessType;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabPanel;
import org.chromium.chrome.browser.contextmenu.ChromeContextMenuItem.Item;
import org.chromium.chrome.browser.firstrun.FirstRunStatus;
import org.chromium.chrome.browser.locale.LocaleManager;
import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
import org.chromium.chrome.browser.share.LensUtils;
import org.chromium.chrome.browser.share.ShareHelper;
import org.chromium.chrome.browser.share.ShareParams;
import org.chromium.chrome.browser.util.UrlUtilities;
import org.chromium.components.search_engines.TemplateUrlService;
import org.chromium.components.url_formatter.UrlFormatter;
import org.chromium.content_public.browser.BrowserStartupController;
import org.chromium.content_public.common.ContentUrlConstants;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
/**
* A {@link ContextMenuPopulator} used for showing the default Chrome context menu.
*/
public class ChromeContextMenuPopulator implements ContextMenuPopulator {
private static final String TAG = "CCMenuPopulator";
private final ContextMenuItemDelegate mDelegate;
private final @ContextMenuMode int mMode;
/**
* Defines the Groups of each Context Menu Item
*/
@IntDef({ContextMenuGroup.LINK, ContextMenuGroup.IMAGE, ContextMenuGroup.VIDEO})
@Retention(RetentionPolicy.SOURCE)
public @interface ContextMenuGroup {
int LINK = 0;
int IMAGE = 1;
int VIDEO = 2;
}
/**
* Defines the context menu modes
*/
@IntDef({ContextMenuMode.NORMAL, ContextMenuMode.CUSTOM_TAB, ContextMenuMode.WEB_APP})
@Retention(RetentionPolicy.SOURCE)
public @interface ContextMenuMode {
int NORMAL = 0; /* Default mode*/
int CUSTOM_TAB = 1; /* Custom tab mode */
int WEB_APP = 2; /* Full screen mode */
}
static class ContextMenuUma {
// Note: these values must match the ContextMenuOptionAndroid enum in enums.xml.
// Only add values to the end, right before NUM_ENTRIES!
@IntDef({Action.OPEN_IN_NEW_TAB, Action.OPEN_IN_INCOGNITO_TAB, Action.COPY_LINK_ADDRESS,
Action.COPY_EMAIL_ADDRESS, Action.COPY_LINK_TEXT, Action.SAVE_LINK,
Action.SAVE_IMAGE, Action.OPEN_IMAGE, Action.OPEN_IMAGE_IN_NEW_TAB,
Action.SEARCH_BY_IMAGE, Action.LOAD_ORIGINAL_IMAGE, Action.SAVE_VIDEO,
Action.SHARE_IMAGE, Action.OPEN_IN_OTHER_WINDOW, Action.SEND_EMAIL,
Action.ADD_TO_CONTACTS, Action.CALL, Action.SEND_TEXT_MESSAGE,
Action.COPY_PHONE_NUMBER, Action.OPEN_IN_NEW_CHROME_TAB,
Action.OPEN_IN_CHROME_INCOGNITO_TAB, Action.OPEN_IN_BROWSER, Action.OPEN_IN_CHROME,
Action.SHARE_LINK, Action.OPEN_IN_EPHEMERAL_TAB, Action.OPEN_IMAGE_IN_EPHEMERAL_TAB,
Action.DIRECT_SHARE_LINK, Action.DIRECT_SHARE_IMAGE,
Action.SEARCH_WITH_GOOGLE_LENS})
@Retention(RetentionPolicy.SOURCE)
public @interface Action {
int OPEN_IN_NEW_TAB = 0;
int OPEN_IN_INCOGNITO_TAB = 1;
int COPY_LINK_ADDRESS = 2;
int COPY_EMAIL_ADDRESS = 3;
int COPY_LINK_TEXT = 4;
int SAVE_LINK = 5;
int SAVE_IMAGE = 6;
int OPEN_IMAGE = 7;
int OPEN_IMAGE_IN_NEW_TAB = 8;
int SEARCH_BY_IMAGE = 9;
int LOAD_ORIGINAL_IMAGE = 10;
int SAVE_VIDEO = 11;
int SHARE_IMAGE = 12;
int OPEN_IN_OTHER_WINDOW = 13;
int SEND_EMAIL = 14;
int ADD_TO_CONTACTS = 15;
int CALL = 16;
int SEND_TEXT_MESSAGE = 17;
int COPY_PHONE_NUMBER = 18;
int OPEN_IN_NEW_CHROME_TAB = 19;
int OPEN_IN_CHROME_INCOGNITO_TAB = 20;
int OPEN_IN_BROWSER = 21;
int OPEN_IN_CHROME = 22;
int SHARE_LINK = 23;
int OPEN_IN_EPHEMERAL_TAB = 24;
int OPEN_IMAGE_IN_EPHEMERAL_TAB = 25;
// These are used to record DirectShare histograms in RevampedContextMenuCoordinator and
// aren't used in onItemSelected.
int DIRECT_SHARE_LINK = 26;
int DIRECT_SHARE_IMAGE = 27;
int SEARCH_WITH_GOOGLE_LENS = 28;
int NUM_ENTRIES = 29;
}
// Note: these values must match the ContextMenuSaveLinkType enum in enums.xml.
// Only add new values at the end, right before NUM_TYPES. We depend on these specific
// values in UMA histograms.
@IntDef({Type.UNKNOWN, Type.TEXT, Type.IMAGE, Type.AUDIO, Type.VIDEO, Type.PDF})
@Retention(RetentionPolicy.SOURCE)
public @interface Type {
int UNKNOWN = 0;
int TEXT = 1;
int IMAGE = 2;
int AUDIO = 3;
int VIDEO = 4;
int PDF = 5;
int NUM_ENTRIES = 6;
}
// Note: these values must match the ContextMenuSaveImage enum in enums.xml.
// Only add new values at the end, right before NUM_ENTRIES.
@IntDef({TypeSaveImage.LOADED, TypeSaveImage.NOT_DOWNLOADABLE,
TypeSaveImage.DISABLED_AND_IS_NOT_IMAGE_PARAM,
TypeSaveImage.DISABLED_AND_IS_IMAGE_PARAM, TypeSaveImage.SHOWN})
@Retention(RetentionPolicy.SOURCE)
public @interface TypeSaveImage {
int LOADED = 0;
// int FETCHED_LOFI = 1; deprecated
int NOT_DOWNLOADABLE = 2;
int DISABLED_AND_IS_NOT_IMAGE_PARAM = 3;
int DISABLED_AND_IS_IMAGE_PARAM = 4;
int SHOWN = 5;
int NUM_ENTRIES = 6;
}
/**
* Records a histogram entry when the user selects an item from a context menu.
* @param params The ContextMenuParams describing the current context menu.
* @param action The action that the user selected (e.g. ACTION_SAVE_IMAGE).
*/
static void record(ContextMenuParams params, @Action int action) {
String histogramName;
if (params.isVideo()) {
histogramName = "ContextMenu.SelectedOptionAndroid.Video";
} else if (params.isImage()) {
histogramName = params.isAnchor() ? "ContextMenu.SelectedOptionAndroid.ImageLink"
: "ContextMenu.SelectedOptionAndroid.Image";
} else {
assert params.isAnchor();
histogramName = "ContextMenu.SelectedOptionAndroid.Link";
}
RecordHistogram.recordEnumeratedHistogram(histogramName, action, Action.NUM_ENTRIES);
}
/**
* Records the content types when user downloads the file by long pressing the
* save link context menu option.
*/
static void recordSaveLinkTypes(String url) {
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
@Type
int mimeType = Type.UNKNOWN;
if (extension != null) {
String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (type != null) {
if (type.startsWith("text")) {
mimeType = Type.TEXT;
} else if (type.startsWith("image")) {
mimeType = Type.IMAGE;
} else if (type.startsWith("audio")) {
mimeType = Type.AUDIO;
} else if (type.startsWith("video")) {
mimeType = Type.VIDEO;
} else if (type.equals("application/pdf")) {
mimeType = Type.PDF;
}
}
}
RecordHistogram.recordEnumeratedHistogram(
"ContextMenu.SaveLinkType", mimeType, Type.NUM_ENTRIES);
}
/**
* Helper method to record MobileDownload.ContextMenu.SaveImage UMA
* @param type Type to record
*/
static void recordSaveImageUma(int type) {
RecordHistogram.recordEnumeratedHistogram(
"MobileDownload.ContextMenu.SaveImage", type, TypeSaveImage.NUM_ENTRIES);
}
// Note: these values must match the ContextMenuLensSupportStatus enum in enums.xml.
// Only add new values at the end, right before NUM_ENTRIES.
@IntDef({LensSupportStatus.LENS_SUPPORTED, LensSupportStatus.NON_GOOGLE_SEARCH_ENGINE,
LensSupportStatus.ACTIVITY_NOT_ACCESSIBLE, LensSupportStatus.OUT_OF_DATE,
LensSupportStatus.SEARCH_BY_IMAGE_UNAVAILABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface LensSupportStatus {
int LENS_SUPPORTED = 0;
int NON_GOOGLE_SEARCH_ENGINE = 1;
int ACTIVITY_NOT_ACCESSIBLE = 2;
int OUT_OF_DATE = 3;
int SEARCH_BY_IMAGE_UNAVAILABLE = 4;
int NUM_ENTRIES = 5;
}
/**
* Helper method to keep track of cases where the Lens app was not supported.
*/
static void recordLensSupportStatus(@LensSupportStatus int reason) {
RecordHistogram.recordEnumeratedHistogram(
"ContextMenu.LensSupportStatus", reason, LensSupportStatus.NUM_ENTRIES);
}
}
/**
* Builds a {@link ChromeContextMenuPopulator}.
* @param delegate The {@link ContextMenuItemDelegate} that will be notified with actions
* to perform when menu items are selected.
* @param mode Defines the context menu mode
*/
public ChromeContextMenuPopulator(ContextMenuItemDelegate delegate, @ContextMenuMode int mode) {
mDelegate = delegate;
mMode = mode;
}
@Override
public void onDestroy() {
mDelegate.onDestroy();
}
/**
* Gets the link of the item or the alternate text of an image.
* @return A string with either the link or with the alternate text.
*/
public static String createHeaderText(ContextMenuParams params) {
if (!isEmptyUrl(params.getLinkUrl())) {
return getUrlText(params);
} else if (!TextUtils.isEmpty(params.getTitleText())) {
return params.getTitleText();
}
return "";
}
/**
* Gets the link of the item or empty text if the Url is empty.
* @return A string with the link or an empty string.
*/
public static String createUrlText(ContextMenuParams params) {
if (!isEmptyUrl(params.getLinkUrl())) {
return getUrlText(params);
}
return "";
}
private static String getUrlText(ContextMenuParams params) {
// The context menu can be created without native library
// being loaded. Only use native URL formatting methods
// if the native libraries have been loaded.
if (BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
.isFullBrowserStarted()) {
return UrlFormatter.formatUrlForDisplayOmitHTTPScheme(params.getLinkUrl());
}
return params.getLinkUrl();
}
@Override
public List<Pair<Integer, List<ContextMenuItem>>> buildContextMenu(
ContextMenu menu, Context context, ContextMenuParams params) {
boolean hasSaveImage = false;
// clang-format off
List<Pair<Integer, List<ContextMenuItem>>> groupedItems = new ArrayList<>();
// clang-format on
if (params.isAnchor()) {
List<ContextMenuItem> linkTab = new ArrayList<>();
if (FirstRunStatus.getFirstRunFlowComplete() && mMode == ContextMenuMode.NORMAL
&& !isEmptyUrl(params.getUrl())
&& UrlUtilities.isAcceptedScheme(params.getUrl())) {
linkTab.add(new ChromeContextMenuItem(Item.OPEN_IN_NEW_TAB));
if (!mDelegate.isIncognito() && mDelegate.isIncognitoSupported()) {
linkTab.add(new ChromeContextMenuItem(Item.OPEN_IN_INCOGNITO_TAB));
}
if (mDelegate.isOpenInOtherWindowSupported()) {
linkTab.add(new ChromeContextMenuItem(Item.OPEN_IN_OTHER_WINDOW));
}
if (EphemeralTabPanel.isSupported()) {
linkTab.add(new ChromeContextMenuItem(Item.OPEN_IN_EPHEMERAL_TAB));
}
}
if (!MailTo.isMailTo(params.getLinkUrl())
&& !UrlUtilities.isTelScheme(params.getLinkUrl())) {
linkTab.add(new ChromeContextMenuItem(Item.COPY_LINK_ADDRESS));
if (!params.getLinkText().trim().isEmpty() && !params.isImage()) {
linkTab.add(new ChromeContextMenuItem(Item.COPY_LINK_TEXT));
}
}
if (FirstRunStatus.getFirstRunFlowComplete()) {
if (!mDelegate.isIncognito()
&& UrlUtilities.isDownloadableScheme(params.getLinkUrl())) {
linkTab.add(new ChromeContextMenuItem(Item.SAVE_LINK_AS));
}
linkTab.add(new ShareContextMenuItem(
R.string.contextmenu_share_link, R.id.contextmenu_share_link, true));
if (UrlUtilities.isTelScheme(params.getLinkUrl())) {
if (mDelegate.supportsCall()) {
linkTab.add(new ChromeContextMenuItem(Item.CALL));
}
if (mDelegate.supportsSendTextMessage()) {
linkTab.add(new ChromeContextMenuItem(Item.SEND_MESSAGE));
}
if (mDelegate.supportsAddToContacts()) {
linkTab.add(new ChromeContextMenuItem(Item.ADD_TO_CONTACTS));
}
}
if (MailTo.isMailTo(params.getLinkUrl())) {
if (mDelegate.supportsSendEmailMessage()) {
linkTab.add(new ChromeContextMenuItem(Item.SEND_MESSAGE));
}
if (!TextUtils.isEmpty(MailTo.parse(params.getLinkUrl()).getTo())
&& mDelegate.supportsAddToContacts()) {
linkTab.add(new ChromeContextMenuItem(Item.ADD_TO_CONTACTS));
}
}
}
if (UrlUtilities.isTelScheme(params.getLinkUrl())
|| MailTo.isMailTo(params.getLinkUrl())) {
linkTab.add(new ChromeContextMenuItem(Item.COPY));
}
if (!linkTab.isEmpty()) {
groupedItems.add(new Pair<>(R.string.contextmenu_link_title, linkTab));
}
}
if (params.isImage() && FirstRunStatus.getFirstRunFlowComplete()) {
List<ContextMenuItem> imageTab = new ArrayList<>();
boolean isSrcDownloadableScheme = UrlUtilities.isDownloadableScheme(params.getSrcUrl());
// Avoid showing open image option for same image which is already opened.
if (mMode == ContextMenuMode.CUSTOM_TAB
&& !mDelegate.getPageUrl().equals(params.getSrcUrl())) {
imageTab.add(new ChromeContextMenuItem(Item.OPEN_IMAGE));
}
if (mMode == ContextMenuMode.NORMAL) {
imageTab.add(new ChromeContextMenuItem(Item.OPEN_IMAGE_IN_NEW_TAB));
}
if (EphemeralTabPanel.isSupported()) {
imageTab.add(new ChromeContextMenuItem(Item.OPEN_IMAGE_IN_EPHEMERAL_TAB));
}
if (isSrcDownloadableScheme) {
imageTab.add(new ChromeContextMenuItem(Item.SAVE_IMAGE));
hasSaveImage = true;
}
if (mMode == ContextMenuMode.CUSTOM_TAB || mMode == ContextMenuMode.NORMAL) {
final TemplateUrlService templateUrlServiceInstance = getTemplateUrlService();
final boolean enableGoogleLensFeature = ChromeFeatureList.isEnabled(
ChromeFeatureList.CONTEXT_MENU_SEARCH_WITH_GOOGLE_LENS);
if (isSrcDownloadableScheme && templateUrlServiceInstance.isLoaded()
&& templateUrlServiceInstance.isSearchByImageAvailable()
&& templateUrlServiceInstance.getDefaultSearchEngineTemplateUrl()
!= null
&& !LocaleManager.getInstance().needToCheckForSearchEnginePromo()) {
// All behavior relating to Lens integration is gated by Feature Flag.
if (enableGoogleLensFeature
&& shouldShowLensMenuItemAndRecordMetrics(
context, templateUrlServiceInstance)) {
imageTab.add(new ChromeContextMenuItem(Item.SEARCH_WITH_GOOGLE_LENS));
} else {
imageTab.add(new ChromeContextMenuItem(Item.SEARCH_BY_IMAGE));
}
} else if (enableGoogleLensFeature) {
ContextMenuUma.recordLensSupportStatus(
ContextMenuUma.LensSupportStatus.SEARCH_BY_IMAGE_UNAVAILABLE);
}
}
imageTab.add(new ShareContextMenuItem(
R.string.contextmenu_share_image, R.id.contextmenu_share_image, false));
recordSaveImageContextMenuResult(isSrcDownloadableScheme);
groupedItems.add(new Pair<>(R.string.contextmenu_image_title, imageTab));
}
if (params.isVideo() && FirstRunStatus.getFirstRunFlowComplete() && params.canSaveMedia()
&& UrlUtilities.isDownloadableScheme(params.getSrcUrl())) {
List<ContextMenuItem> videoTab = new ArrayList<>();
videoTab.add(new ChromeContextMenuItem(Item.SAVE_VIDEO));
groupedItems.add(new Pair<>(R.string.contextmenu_video_title, videoTab));
}
if (mMode != ContextMenuMode.NORMAL && FirstRunStatus.getFirstRunFlowComplete()) {
List<ContextMenuItem> tab = groupedItems.isEmpty()
? new ArrayList<>()
: groupedItems
.get(mMode == ContextMenuMode.CUSTOM_TAB ? 0
: groupedItems.size() - 1)
.second;
if (mMode == ContextMenuMode.WEB_APP) {
tab.add(new ChromeContextMenuItem(Item.OPEN_IN_CHROME));
} else if (mMode == ContextMenuMode.CUSTOM_TAB) {
boolean addNewEntries = false;
try {
URI uri = new URI(params.getUrl());
if (!UrlUtilities.isInternalScheme(uri) && !isEmptyUrl(params.getUrl())) {
addNewEntries = true;
}
} catch (URISyntaxException ignore) {
}
if (ChromePreferenceManager.getInstance().readBoolean(
ChromePreferenceManager.CHROME_DEFAULT_BROWSER, false)
&& addNewEntries) {
if (mDelegate.isIncognitoSupported()) {
tab.add(0, new ChromeContextMenuItem(Item.OPEN_IN_CHROME_INCOGNITO_TAB));
}
tab.add(0, new ChromeContextMenuItem(Item.OPEN_IN_NEW_CHROME_TAB));
} else if (addNewEntries) {
tab.add(0, new ChromeContextMenuItem(Item.OPEN_IN_BROWSER_ID));
}
}
if (groupedItems.isEmpty() && !tab.isEmpty()) {
groupedItems.add(new Pair<>(R.string.contextmenu_link_title, tab));
}
}
if (!groupedItems.isEmpty()
&& BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
.isFullBrowserStarted()) {
if (!hasSaveImage) {
ContextMenuUma.recordSaveImageUma(params.isImage()
? ContextMenuUma.TypeSaveImage.DISABLED_AND_IS_IMAGE_PARAM
: ContextMenuUma.TypeSaveImage.DISABLED_AND_IS_NOT_IMAGE_PARAM);
} else {
ContextMenuUma.recordSaveImageUma(ContextMenuUma.TypeSaveImage.SHOWN);
}
}
return groupedItems;
}
@Override
public boolean onItemSelected(ContextMenuHelper helper, ContextMenuParams params, int itemId) {
if (itemId == R.id.contextmenu_open_in_new_tab) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IN_NEW_TAB);
mDelegate.onOpenInNewTab(params.getUrl(), params.getReferrer());
} else if (itemId == R.id.contextmenu_open_in_incognito_tab) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IN_INCOGNITO_TAB);
mDelegate.onOpenInNewIncognitoTab(params.getUrl());
} else if (itemId == R.id.contextmenu_open_in_other_window) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IN_OTHER_WINDOW);
mDelegate.onOpenInOtherWindow(params.getUrl(), params.getReferrer());
} else if (itemId == R.id.contextmenu_open_in_ephemeral_tab) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IN_EPHEMERAL_TAB);
mDelegate.onOpenInEphemeralTab(params.getUrl(), params.getLinkText());
} else if (itemId == R.id.contextmenu_open_image) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IMAGE);
mDelegate.onOpenImageUrl(params.getSrcUrl(), params.getReferrer());
} else if (itemId == R.id.contextmenu_open_image_in_new_tab) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IMAGE_IN_NEW_TAB);
mDelegate.onOpenImageInNewTab(params.getSrcUrl(), params.getReferrer());
} else if (itemId == R.id.contextmenu_open_image_in_ephemeral_tab) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IMAGE_IN_EPHEMERAL_TAB);
String title = params.getTitleText();
if (TextUtils.isEmpty(title)) {
title = URLUtil.guessFileName(params.getSrcUrl(), null, null);
}
mDelegate.onOpenInEphemeralTab(params.getSrcUrl(), title);
} else if (itemId == R.id.contextmenu_copy_link_address) {
ContextMenuUma.record(params, ContextMenuUma.Action.COPY_LINK_ADDRESS);
mDelegate.onSaveToClipboard(
params.getUnfilteredLinkUrl(), ContextMenuItemDelegate.ClipboardType.LINK_URL);
} else if (itemId == R.id.contextmenu_call) {
ContextMenuUma.record(params, ContextMenuUma.Action.CALL);
mDelegate.onCall(params.getLinkUrl());
} else if (itemId == R.id.contextmenu_send_message) {
if (MailTo.isMailTo(params.getLinkUrl())) {
ContextMenuUma.record(params, ContextMenuUma.Action.SEND_EMAIL);
mDelegate.onSendEmailMessage(params.getLinkUrl());
} else if (UrlUtilities.isTelScheme(params.getLinkUrl())) {
ContextMenuUma.record(params, ContextMenuUma.Action.SEND_TEXT_MESSAGE);
mDelegate.onSendTextMessage(params.getLinkUrl());
}
} else if (itemId == R.id.contextmenu_add_to_contacts) {
ContextMenuUma.record(params, ContextMenuUma.Action.ADD_TO_CONTACTS);
mDelegate.onAddToContacts(params.getLinkUrl());
} else if (itemId == R.id.contextmenu_copy) {
if (MailTo.isMailTo(params.getLinkUrl())) {
ContextMenuUma.record(params, ContextMenuUma.Action.COPY_EMAIL_ADDRESS);
mDelegate.onSaveToClipboard(MailTo.parse(params.getLinkUrl()).getTo(),
ContextMenuItemDelegate.ClipboardType.LINK_URL);
} else if (UrlUtilities.isTelScheme(params.getLinkUrl())) {
ContextMenuUma.record(params, ContextMenuUma.Action.COPY_PHONE_NUMBER);
mDelegate.onSaveToClipboard(UrlUtilities.getTelNumber(params.getLinkUrl()),
ContextMenuItemDelegate.ClipboardType.LINK_URL);
}
} else if (itemId == R.id.contextmenu_copy_link_text) {
ContextMenuUma.record(params, ContextMenuUma.Action.COPY_LINK_TEXT);
mDelegate.onSaveToClipboard(
params.getLinkText(), ContextMenuItemDelegate.ClipboardType.LINK_TEXT);
} else if (itemId == R.id.contextmenu_save_image) {
ContextMenuUma.record(params, ContextMenuUma.Action.SAVE_IMAGE);
if (mDelegate.startDownload(params.getSrcUrl(), false)) {
helper.startContextMenuDownload(
false, mDelegate.isDataReductionProxyEnabledForURL(params.getSrcUrl()));
}
} else if (itemId == R.id.contextmenu_save_video) {
ContextMenuUma.record(params, ContextMenuUma.Action.SAVE_VIDEO);
if (mDelegate.startDownload(params.getSrcUrl(), false)) {
helper.startContextMenuDownload(false, false);
}
} else if (itemId == R.id.contextmenu_save_link_as) {
ContextMenuUma.record(params, ContextMenuUma.Action.SAVE_LINK);
String url = params.getUnfilteredLinkUrl();
if (mDelegate.startDownload(url, true)) {
ContextMenuUma.recordSaveLinkTypes(url);
helper.startContextMenuDownload(true, false);
}
} else if (itemId == R.id.contextmenu_share_link) {
ContextMenuUma.record(params, ContextMenuUma.Action.SHARE_LINK);
ShareParams linkShareParams =
new ShareParams.Builder(helper.getActivity(), params.getUrl(), params.getUrl())
.setShareDirectly(false)
.setSaveLastUsed(true)
.build();
ShareHelper.share(linkShareParams);
} else if (itemId == R.id.contextmenu_search_with_google_lens) {
ContextMenuUma.record(params, ContextMenuUma.Action.SEARCH_WITH_GOOGLE_LENS);
helper.searchWithGoogleLens(mDelegate.isIncognito());
} else if (itemId == R.id.contextmenu_search_by_image) {
ContextMenuUma.record(params, ContextMenuUma.Action.SEARCH_BY_IMAGE);
helper.searchForImage();
} else if (itemId == R.id.contextmenu_share_image) {
ContextMenuUma.record(params, ContextMenuUma.Action.SHARE_IMAGE);
helper.shareImage();
} else if (itemId == R.id.contextmenu_open_in_chrome) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IN_CHROME);
mDelegate.onOpenInChrome(params.getUrl(), params.getPageUrl());
} else if (itemId == R.id.contextmenu_open_in_new_chrome_tab) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IN_NEW_CHROME_TAB);
mDelegate.onOpenInNewChromeTabFromCCT(params.getUrl(), false);
} else if (itemId == R.id.contextmenu_open_in_chrome_incognito_tab) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IN_CHROME_INCOGNITO_TAB);
mDelegate.onOpenInNewChromeTabFromCCT(params.getUrl(), true);
} else if (itemId == R.id.contextmenu_open_in_browser_id) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IN_BROWSER);
mDelegate.onOpenInDefaultBrowser(params.getUrl());
} else {
assert false;
}
return true;
}
/**
* @return The service that handles TemplateUrls.
*/
protected TemplateUrlService getTemplateUrlService() {
return TemplateUrlServiceFactory.get();
}
/**
* Checks whether a url is empty or blank.
* @param url The url need to be checked.
* @return True if the url is empty or "about:blank".
*/
private static boolean isEmptyUrl(String url) {
return TextUtils.isEmpty(url) || url.equals(ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
}
/**
* Record the UMA related to save image context menu option.
* @param isDownloadableScheme The image is downloadable.
*/
private void recordSaveImageContextMenuResult(boolean isDownloadableScheme) {
if (!BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
.isFullBrowserStarted()) {
return;
}
ContextMenuUma.recordSaveImageUma(ContextMenuUma.TypeSaveImage.LOADED);
if (!isDownloadableScheme) {
ContextMenuUma.recordSaveImageUma(ContextMenuUma.TypeSaveImage.NOT_DOWNLOADABLE);
}
}
/**
* Whether the lens menu item should be shown based on a set of application
* compatibility checks.
*
* @param context The current application context
* @param TemplateUrlService The service which identifies the current default search engine.
* @return Whether to show the menu item
*/
private boolean shouldShowLensMenuItemAndRecordMetrics(
Context context, TemplateUrlService templateUrlServiceInstance) {
String versionName = LensUtils.getLensActivityVersionNameIfAvailable(context);
if (!templateUrlServiceInstance.isDefaultSearchEngineGoogle()) {
ContextMenuUma.recordLensSupportStatus(
ContextMenuUma.LensSupportStatus.NON_GOOGLE_SEARCH_ENGINE);
return false;
}
if (TextUtils.isEmpty(versionName)) {
ContextMenuUma.recordLensSupportStatus(
ContextMenuUma.LensSupportStatus.ACTIVITY_NOT_ACCESSIBLE);
return false;
}
if (LensUtils.isAgsaVersionBelowMinimum(versionName)) {
ContextMenuUma.recordLensSupportStatus(ContextMenuUma.LensSupportStatus.OUT_OF_DATE);
return false;
}
ContextMenuUma.recordLensSupportStatus(ContextMenuUma.LensSupportStatus.LENS_SUPPORTED);
return true;
}
}