
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