All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.smartdevicelink.managers.screen.menu.MenuCell Maven / Gradle / Ivy

/*
 * Copyright (c) 2019 Livio, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided with the
 * distribution.
 *
 * Neither the name of the Livio Inc. nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package com.smartdevicelink.managers.screen.menu;

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

import com.smartdevicelink.managers.file.filetypes.SdlArtwork;
import com.smartdevicelink.proxy.rpc.enums.MenuLayout;
import com.smartdevicelink.util.DebugTool;

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

public class MenuCell implements Cloneable {

    /**
     * The cell's text to be displayed
     */
    private String title;

    /**
     * The cell's icon to be displayed
     */
    private SdlArtwork icon;

    /**
     * The strings the user can say to activate this voice command
     */
    private List voiceCommands;

    /**
     * If this is not null, this cell will be a sub-menu button, displaying the sub-cells in a menu when pressed.
     */
    private List subCells;

    /**
     * The listener that will be called when the command is activated
     */
    private MenuSelectionListener menuSelectionListener;

    /**
     * Used internally for cell ordering
     */
    private int parentCellId;

    /**
     * Used internally for cell ordering
     */
    private int cellId;

    /**
     * The submenu's layout that the subCells will be shown in. If `null`, the default submenu
     * layout set via the screen manager's `MenuConfiguration` will be used.
     */
    private MenuLayout subMenuLayout;

    /**
     * MAX ID for cells - Cannot use Integer.MAX_INT as the value is too high.
     */
    private static final int MAX_ID = 2000000000;

    /**
     * secondaryText and tertiaryText - additional text to be displayed
     */
    private String secondaryText, tertiaryText;

    /**
     * secondaryArtwork - a secondary icon to be displayed
     */
    private SdlArtwork secondaryArtwork;

    /**
     * Primary text of the cell to be displayed on the module. Used to distinguish cells with the
     * same `title` but other fields are different. This is autogenerated by the screen manager.
     * This will not be used when connected to modules supporting RPC 7.1+.
     */
    private String uniqueTitle;

    // CONSTRUCTORS

    // SINGLE MENU ITEM CONSTRUCTORS

    /**
     * Creates a new MenuCell Object with multiple parameters set
     *
     * @param title         The cell's primary text
     * @param icon          The cell's image
     * @param voiceCommands Voice commands that will activate the menu cell
     * @param listener      Calls the code that will be run when the menu cell is selected
     */
    @Deprecated
    public MenuCell(@NonNull String title, @Nullable SdlArtwork icon, @Nullable List voiceCommands, @Nullable MenuSelectionListener listener) {
        setTitle(title); // title is the only required param
        setUniqueTitle(title);
        setIcon(icon);
        setVoiceCommands(voiceCommands);
        setMenuSelectionListener(listener);
        setCellId(MAX_ID);
        setParentCellId(MAX_ID);
    }

    /**
     * Creates a new MenuCell Object with multiple parameters and optional fields set
     *
     * @param title             The cell's primary text
     * @param secondaryText     The cell's secondary text
     * @param tertiaryText      The cell's tertiary text
     * @param icon              The cell's image
     * @param secondaryArtwork  The cell's secondary image
     * @param voiceCommands     Voice commands that will activate the menu cell
     * @param listener          Calls the code that will be run when the menu cell is selected
     */
    public MenuCell(@NonNull String title, @Nullable String secondaryText, @Nullable String tertiaryText, @Nullable SdlArtwork icon, @Nullable SdlArtwork secondaryArtwork, @Nullable List voiceCommands, @Nullable MenuSelectionListener listener) {
        setTitle(title); // title is the only required param
        setUniqueTitle(title);
        setSecondaryText(secondaryText);
        setTertiaryText(tertiaryText);
        setIcon(icon);
        setSecondaryArtwork(secondaryArtwork);
        setVoiceCommands(voiceCommands);
        setMenuSelectionListener(listener);
        setCellId(MAX_ID);
        setParentCellId(MAX_ID);
    }

    // CONSTRUCTOR FOR CELL THAT WILL LINK TO SUB MENU

    /**
     * Creates a new MenuCell Object with multiple parameters set
     * NOTE: because this has sub-cells, there does not need to be a listener
     *
     * @param title         The cell's primary text
     * @param subMenuLayout The submenu's layout that the subCells will be shown in. If `null`, the
     *                      default submenu layout in the screen manager's `MenuConfiguration` will be used.
     * @param icon          The cell's image
     * @param subCells      The sub-cells for the sub menu that will appear when the cell is selected
     */
    @Deprecated
    public MenuCell(@NonNull String title, @Nullable MenuLayout subMenuLayout, @Nullable SdlArtwork icon, @Nullable List subCells) {
        setTitle(title); // title is the only required param
        setUniqueTitle(title);
        setSubMenuLayout(subMenuLayout);
        setIcon(icon);
        setSubCells(subCells);
        setCellId(MAX_ID);
        setParentCellId(MAX_ID);
    }

    /**
     * Creates a new MenuCell Object with multiple parameters and optional fields set
     * NOTE: because this has sub-cells, there does not need to be a listener
     *
     * @param title         The cell's primary text
     * @param secondaryText     The cell's secondary text
     * @param tertiaryText      The cell's tertiary text
     * @param subMenuLayout The submenu's layout that the subCells will be shown in. If `null`, the
     *                      default submenu layout in the screen manager's `MenuConfiguration` will be used.
     * @param icon          The cell's image
     * @param secondaryArtwork  The cell's secondary image
     * @param subCells      The sub-cells for the sub menu that will appear when the cell is selected
     */
    public MenuCell(@NonNull String title, @Nullable String secondaryText, @Nullable String tertiaryText, @Nullable MenuLayout subMenuLayout, @Nullable SdlArtwork icon, @Nullable SdlArtwork secondaryArtwork, @Nullable List subCells) {
        setTitle(title); // title is the only required param
        setUniqueTitle(title);
        setSecondaryText(secondaryText);
        setTertiaryText(tertiaryText);
        setSubMenuLayout(subMenuLayout);
        setIcon(icon);
        setSecondaryArtwork(secondaryArtwork);
        setSubCells(subCells);
        setCellId(MAX_ID);
        setParentCellId(MAX_ID);
    }

    // SETTERS / GETTERS

    // PUBLIC METHODS

    /**
     * Sets the title of the menu cell
     *
     * @param title - the title of the cell. Required
     */
    public void setTitle(@NonNull String title) {
        this.title = title;
    }

    /**
     * Gets the title of the menu cell
     *
     * @return The title of the cell object
     */
    public String getTitle() {
        return title;
    }

    /**
     * Sets the icon of the menu cell
     *
     * @param icon - the icon being set, of type {@link SdlArtwork}
     */
    public void setIcon(SdlArtwork icon) {
        this.icon = icon;
    }

    /**
     * Gets the icon for the cell
     *
     * @return the {@link SdlArtwork} icon for the cell
     */
    public SdlArtwork getIcon() {
        return icon;
    }

    /**
     * A list of Strings that will be used for voice commands
     *
     * @param voiceCommands - the string list used by the IVI system for voice commands
     */
    public void setVoiceCommands(List voiceCommands) {
        this.voiceCommands = voiceCommands;
    }

    /**
     * the string list used by the IVI system for voice commands
     *
     * @return The String List used by the menu cell object for voice commands
     */
    public List getVoiceCommands() {
        return voiceCommands;
    }

    /**
     * The list of MenuCells that can be set as subCells
     *
     * @param subCells - the list of subCells for this menu item
     */
    public void setSubCells(List subCells) {
        this.subCells = subCells;
    }

    /**
     * The list of subCells for this menu item
     *
     * @return a list of MenuCells that are the subCells for this menu item
     */
    public List getSubCells() {
        return subCells;
    }

    /**
     * The listener for when a menu item is selected
     *
     * @param menuSelectionListener the listener for this menuCell object
     */
    public void setMenuSelectionListener(MenuSelectionListener menuSelectionListener) {
        this.menuSelectionListener = menuSelectionListener;
    }

    /**
     * The listener that gets triggered when the menuCell object is selected
     *
     * @return the MenuSelectionListener for the cell
     */
    public MenuSelectionListener getMenuSelectionListener() {
        return menuSelectionListener;
    }

    /**
     * The submenu's layout that the subCells will be shown in. If `null`, the default submenu
     * layout set via the screen manager's `MenuConfiguration` will be used.
     *
     * @param subMenuLayout - the layout used for the sub menu
     */
    public void setSubMenuLayout(MenuLayout subMenuLayout) {
        this.subMenuLayout = subMenuLayout;
    }

    /**
     * The submenu's layout that the subCells will be shown in. If `null`, the default submenu
     * layout set via the screen manager's `MenuConfiguration` will be used.
     *
     * @return - the layout used for the sub menu
     */
    public MenuLayout getSubMenuLayout() {
        return this.subMenuLayout;
    }

    // INTERNALLY USED METHODS

    /**
     * Set the cell Id.
     *
     * @param cellId - the cell Id
     */
    void setCellId(int cellId) {
        this.cellId = cellId;
    }

    /**
     * Get the cellId
     *
     * @return the cellId for this menuCell
     */
    int getCellId() {
        return cellId;
    }

    /**
     * Sets the ParentCellId
     *
     * @param parentCellId the parent cell's Id
     */
    void setParentCellId(int parentCellId) {
        this.parentCellId = parentCellId;
    }

    /**
     * Get the parent cell's Id
     *
     * @return the parent cell's Id
     */
    int getParentCellId() {
        return parentCellId;
    }

    /**
     * Sets the secondaryText
     *
     * @param secondaryText the cell's secondaryText
     */
    public void setSecondaryText(String secondaryText) {
        this.secondaryText = secondaryText;
    }

    /**
     * Get the cell's secondaryText
     *
     * @return the cell's secondaryText
     */
    public String getSecondaryText() {
        return secondaryText;
    }

    /**
     * Sets the tertiaryText
     *
     * @param tertiaryText the cell's tertiaryText
     */
    public void setTertiaryText(String tertiaryText) {
        this.tertiaryText = tertiaryText;
    }


    /**
     * Get the cell's tertiaryText
     *
     * @return the cell's tertiaryText
     */
    public String getTertiaryText() {
        return tertiaryText;
    }

    /**
     * Sets the secondaryArtwork
     *
     * @param secondaryArtwork the cell's secondaryArtwork
     */
    public void setSecondaryArtwork(SdlArtwork secondaryArtwork) {
        this.secondaryArtwork = secondaryArtwork;
    }

    /**
     * Get the cell's secondaryArtwork
     *
     * @return the cell's secondaryArtwork
     */
    public SdlArtwork getSecondaryArtwork() {
        return secondaryArtwork;
    }

    /**
     * NOTE: USED INTERNALLY
     * Set the uniqueTitle.
     *
     * @param uniqueTitle - the uniqueTitle to be used in place of primary title when core does not support identical names for MenuCells
     */
    void setUniqueTitle(String uniqueTitle) {
        this.uniqueTitle = uniqueTitle;
    }

    /**
     * NOTE: USED INTERNALLY
     * Get the uniqueTitle that was used in place of the primary title
     *
     * @return the uniqueTitle for this MenuCell
     */
    String getUniqueTitle() {
        return uniqueTitle;
    }

    // HELPER

    boolean isSubMenuCell() {
        return getSubCells() != null;
    }

    /**
     * Note: You should compare using the {@link #equals(Object)} method. 
* Hash the parameters of the object and return the result for comparison * For each param, increase the rotation distance by one. * It is necessary to rotate each of our properties because a simple bitwise OR will produce equivalent results if, for example: * Object 1: getText() = "Hi", getSecondaryText() = "Hello" * Object 2: getText() = "Hello", getSecondaryText() = "Hi" * * @return the hash code as an int */ @Override public int hashCode() { int result = 1; result += ((getTitle() == null) ? 0 : Integer.rotateLeft(getTitle().hashCode(), 1)); result += ((getIcon() == null || getIcon().getName() == null) ? 0 : Integer.rotateLeft(getIcon().getName().hashCode(), 2)); result += ((getVoiceCommands() == null) ? 0 : Integer.rotateLeft(getVoiceCommands().hashCode(), 3)); result += ((getSubCells() == null) ? 0 : Integer.rotateLeft(1, 4)); result += ((getSecondaryText() == null) ? 0 : Integer.rotateLeft(getSecondaryText().hashCode(), 5)); result += ((getTertiaryText() == null) ? 0 : Integer.rotateLeft(getTertiaryText().hashCode(), 6)); result += ((getSecondaryArtwork() == null || getSecondaryArtwork().getName() == null) ? 0 : Integer.rotateLeft(getSecondaryArtwork().getName().hashCode(), 7)); result += ((getSubMenuLayout() == null) ? 0 : Integer.rotateLeft(getSubMenuLayout().hashCode(), 8)); return result; } private int hashCodeWithUniqueTitle() { int result = hashCode(); result += ((getUniqueTitle() == null) ? 0 : Integer.rotateLeft(getUniqueTitle().hashCode(), 9)); return result; } /** * Uses our custom hashCode for MenuCell objects * * @param o - The object to compare * @return boolean of whether the objects are the same or not */ @Override public boolean equals(Object o) { if (o == null) { return false; } // if this is the same memory address, its the same if (this == o) return true; // if this is not an instance of this class, not the same if (!(o instanceof MenuCell)) return false; // if we get to this point, create the hashes and compare them return hashCode() == o.hashCode(); } /** * Uses our custom hashCode for MenuCell objects. This method takes UniqueTitle into consideration when doing the equality check * * @param o - The object to compare * @return boolean of whether the objects are the same or not */ boolean equalsWithUniqueTitle(MenuCell o) { if (o == null) { return false; } // if this is the same memory address, its the same if (this == o) return true; // if we get to this point, create the hashes and compare them return hashCodeWithUniqueTitle() == o.hashCodeWithUniqueTitle(); } /** * Creates a deep copy of the object * * @return deep copy of the object, null if an exception occurred */ @Override public MenuCell clone() { try { MenuCell clone = (MenuCell) super.clone(); if (this.icon != null) { clone.icon = this.icon.clone(); } if (this.secondaryArtwork != null) { clone.secondaryArtwork = this.secondaryArtwork.clone(); } if (this.subCells != null) { ArrayList cloneSubCells = new ArrayList<>(); for (MenuCell subCell : subCells) { cloneSubCells.add(subCell.clone()); } clone.subCells = cloneSubCells; } return clone; } catch (CloneNotSupportedException e) { if (DebugTool.isDebugEnabled()) { throw new RuntimeException("Clone not supported by super class"); } } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy