chromium/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsDropdownEmbedder.java

// Copyright 2020 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.omnibox.suggestions;

import android.annotation.SuppressLint;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import org.chromium.base.Callback;

import java.util.Objects;

/** Provider of capabilities required to embed the omnibox suggestion list into the UI. */
public interface OmniboxSuggestionsDropdownEmbedder {

    /**
     * POD type that encapsulates the "alignment" (position, width, padding) of the omnibox
     * dropdown.
     */
    class OmniboxAlignment {

        public static final OmniboxAlignment UNSPECIFIED =
                new OmniboxAlignment(-1, -1, -1, -1, -1, -1);
        public final int left;
        public final int top;
        public final int width;
        public final int height;
        public final int paddingLeft;
        public final int paddingRight;

        public OmniboxAlignment(
                int left, int top, int width, int height, int paddingLeft, int paddingRight) {
            this.left = left;
            this.top = top;
            this.width = width;
            this.paddingLeft = paddingLeft;
            this.paddingRight = paddingRight;
            this.height = height;
        }

        @Override
        public int hashCode() {
            return Objects.hash(left, top, width, paddingLeft, paddingRight);
        }

        @Override
        public boolean equals(@Nullable Object obj) {
            if (!(obj instanceof OmniboxAlignment)) return false;
            OmniboxAlignment other = (OmniboxAlignment) obj;
            return other.left == this.left
                    && other.top == this.top
                    && other.width == this.width
                    && other.height == this.height
                    && other.paddingLeft == this.paddingLeft
                    && other.paddingRight == this.paddingRight;
        }

        @SuppressLint("DefaultLocale")
        @NonNull
        @Override
        public String toString() {
            return String.format(
                    "OmniboxAlignment left: %d top: %d width: %d height: %d paddingLeft: %d"
                            + " paddingRight: %d",
                    left, top, width, height, paddingLeft, paddingRight);
        }

        /**
         * Returns whether the difference from the given alignment object is solely in terms of left
         * or padding.
         */
        public boolean isOnlyHorizontalDifference(@Nullable OmniboxAlignment other) {
            if (other == null) return false;
            return (this.left != other.left
                            || this.paddingLeft != other.paddingLeft
                                    && this.paddingRight != other.paddingRight)
                    && (this.top == other.top && this.width == other.width);
        }

        /**
         * Returns whether the width of the given OmniboxAlignment differs from this alignment
         * object's width. Returns true for a null argument.
         */
        public boolean doesWidthDiffer(@Nullable OmniboxAlignment other) {
            if (other == null) return true;
            return this.width != other.width;
        }
    }

    /**
     * Adds an observer of alignment changes. The supplied callback will be invoked when alignment
     * is recalculated.
     */
    OmniboxAlignment addAlignmentObserver(Callback<OmniboxAlignment> obs);

    /**
     * Remove an observer of alignment changes. The supplied callback will be no longer invoked when
     * alignment is recalculated.
     */
    void removeAlignmentObserver(Callback<OmniboxAlignment> obs);

    /**
     * Returns the current alignment values, but does not recalculate them. Will not return null but
     * may return {@link OmniboxAlignment.UNSPECIFIED} if there is not a currently valid alignment.
     */
    @NonNull
    OmniboxAlignment getCurrentAlignment();

    /** Return whether the suggestions are being rendered in the tablet UI. */
    boolean isTablet();

    /**
     * The dropdown must call this when it is attached to the window to start the process of
     * alignment recalculation. Updates are skipped prior to this point to avoid repeated, unused
     * calculation of alignment values.
     */
    void onAttachedToWindow();

    /**
     * The dropdown should call this when it is detached from the window to pause the process of
     * alignment recalculation.
     */
    void onDetachedFromWindow();

    /** The vertical translation that should be used during focus animations. */
    float getVerticalTranslationForAnimation();
}