chromium/android_webview/java/src/org/chromium/android_webview/contextmenu/AwContextMenuPopulator.java

// Copyright 2024 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.android_webview.contextmenu;

import static org.chromium.android_webview.contextmenu.AwContextMenuItemProperties.MENU_ID;
import static org.chromium.android_webview.contextmenu.AwContextMenuItemProperties.TEXT;

import android.content.Context;
import android.util.Pair;

import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;

import org.chromium.android_webview.R;
import org.chromium.android_webview.contextmenu.AwContextMenuCoordinator.ListItemType;
import org.chromium.android_webview.contextmenu.AwContextMenuItem.Item;
import org.chromium.components.embedder_support.contextmenu.ChipDelegate;
import org.chromium.components.embedder_support.contextmenu.ContextMenuItemDelegate;
import org.chromium.components.embedder_support.contextmenu.ContextMenuParams;
import org.chromium.components.embedder_support.contextmenu.ContextMenuPopulator;
import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
import org.chromium.ui.modelutil.PropertyModel;

import java.util.ArrayList;
import java.util.List;

/** A {@link ContextMenuPopulator} used for showing the WebView context menu. */
public class AwContextMenuPopulator implements ContextMenuPopulator {
    private final Context mContext;
    private final ContextMenuItemDelegate mItemDelegate;
    private final ContextMenuParams mParams;

    /**
     * Builds a {@link AwContextMenuPopulator}.
     *
     * @param context The {@link Context} used to retrieve the strings.
     * @param itemDelegate The {@link ContextMenuItemDelegate} that will be notified with actions to
     *     perform when menu items are selected.
     * @param params The {@link ContextMenuParams} to populate the menu items.
     */
    public AwContextMenuPopulator(
            Context context, ContextMenuItemDelegate itemDelegate, ContextMenuParams params) {
        mContext = context;
        mItemDelegate = itemDelegate;
        mParams = params;
    }

    @Override
    public List<Pair<Integer, ModelList>> buildContextMenu() {
        List<Pair<Integer, ModelList>> groupedItems = new ArrayList<>();

        ModelList items = new ModelList();

        items.add(createListItem(Item.COPY_LINK_TEXT));
        items.add(createListItem(Item.COPY_LINK_ADDRESS));
        items.add(createListItem(Item.OPEN_IN_BROWSER));

        groupedItems.add(new Pair<>(R.string.context_menu_copy_link_text, items));

        return groupedItems;
    }

    @Override
    public boolean isIncognito() {
        return mItemDelegate.isIncognito();
    }

    @Override
    public String getPageTitle() {
        return mItemDelegate.getPageTitle();
    }

    @Override
    public boolean onItemSelected(int itemId) {
        if (itemId == R.id.contextmenu_copy_link_address) {
            mItemDelegate.onSaveToClipboard(
                    mParams.getUnfilteredLinkUrl().getSpec(),
                    ContextMenuItemDelegate.ClipboardType.LINK_URL);
        } else if (itemId == R.id.contextmenu_copy_link_text) {
            mItemDelegate.onSaveToClipboard(
                    mParams.getLinkText(), ContextMenuItemDelegate.ClipboardType.LINK_TEXT);
        } else if (itemId == R.id.contextmenu_open_in_browser_id) {
            mItemDelegate.onOpenInDefaultBrowser(mParams.getUrl());
        } else {
            assert false;
        }

        return true;
    }

    @Override
    public void onMenuClosed() {}

    @Override
    public @Nullable ChipDelegate getChipDelegate() {
        return null;
    }

    @VisibleForTesting
    public Integer getMenuId(PropertyModel model) {
        return model.get(MENU_ID);
    }

    private ListItem createListItem(@Item int item) {
        PropertyModel model =
                new PropertyModel.Builder(AwContextMenuItemProperties.ALL_KEYS)
                        .with(MENU_ID, AwContextMenuItem.getMenuId(item))
                        .with(TEXT, AwContextMenuItem.getTitle(mContext, item))
                        .build();
        return new ListItem(ListItemType.CONTEXT_MENU_ITEM, model);
    }
}