chromium/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuListView.java

// Copyright 2019 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.chrome.browser.contextmenu;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ListView;

import org.chromium.chrome.R;

/**
 * A custom ListView to be able to set width and height using the contents. Width and height are
 * constrained to make sure the view fits the screen size with margins.
 */
public class ContextMenuListView extends ListView {
    // Whether the max width of this list view is limited by screen width.
    private final boolean mLimitedByScreenWidth;

    public ContextMenuListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mLimitedByScreenWidth = ContextMenuUtils.usePopupContextMenuForContext(context);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(calculateWidth(), MeasureSpec.EXACTLY);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * The value returned by this method is used to set the width of the context menu in {@link
     * onMeasure()}
     *
     * @return The width of the context menu in pixels
     */
    private int calculateWidth() {
        final int windowWidthPx = getResources().getDisplayMetrics().widthPixels;
        final int maxWidthFromRes =
                getResources().getDimensionPixelSize(R.dimen.context_menu_max_width);
        final int lateralMargin =
                getResources().getDimensionPixelSize(R.dimen.context_menu_lateral_margin);

        // This ListView should be inside a FrameLayout with the menu_bg_tinted background. Since
        // the background is a 9-patch, it gets some extra padding automatically, and we should
        // take it into account when calculating the width here.
        final View frame = ((View) getParent());
        assert frame.getId() == R.id.context_menu_frame;
        final int parentLateralPadding = frame.getPaddingLeft();
        final int maxWidth = Math.min(maxWidthFromRes, frame.getMeasuredWidth());

        // When context menu is a popup, the max width with windowWidth - 2 * lateralMargin does not
        // applied since it is presented in a popup window. See https://crbug.com/1314675.
        if (mLimitedByScreenWidth) {
            return maxWidth - 2 * parentLateralPadding;
        }
        return Math.min(maxWidth, windowWidthPx - 2 * lateralMargin) - 2 * parentLateralPadding;
    }
}