diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/NavigationView.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/NavigationView.java index 74b2e04e7af..62ac186e2f3 100644 --- a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/NavigationView.java +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/NavigationView.java @@ -27,7 +27,7 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.services.android.navigation.ui.v5.camera.NavigationCamera; -import com.mapbox.services.android.navigation.ui.v5.instruction.ImageCoordinator; +import com.mapbox.services.android.navigation.ui.v5.instruction.ImageCreator; import com.mapbox.services.android.navigation.ui.v5.instruction.InstructionView; import com.mapbox.services.android.navigation.ui.v5.instruction.NavigationAlertView; import com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap; @@ -712,7 +712,7 @@ private void shutdown() { navigationViewEventDispatcher.onDestroy(navigationViewModel.retrieveNavigation()); mapView.onDestroy(); navigationViewModel.onDestroy(isChangingConfigurations()); - ImageCoordinator.getInstance().shutdown(); + ImageCreator.getInstance().shutdown(); navigationMap = null; } } \ No newline at end of file diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationCoordinator.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationCreator.java similarity index 75% rename from libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationCoordinator.java rename to libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationCreator.java index 1c1a08247b0..57d10b4efee 100644 --- a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationCoordinator.java +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationCreator.java @@ -3,7 +3,6 @@ import android.widget.TextView; import com.mapbox.api.directions.v5.models.BannerComponents; -import com.mapbox.services.android.navigation.ui.v5.instruction.InstructionLoader.BannerComponentNode; import java.util.ArrayList; import java.util.Collections; @@ -17,18 +16,24 @@ * BannerComponents containing abbreviation information and given a list of BannerComponentNodes, * constructed by InstructionLoader. */ -class AbbreviationCoordinator { +class AbbreviationCreator extends NodeCreator { private static final String SINGLE_SPACE = " "; private Map> abbreviations; private TextViewUtils textViewUtils; - AbbreviationCoordinator(TextViewUtils textViewUtils) { - this.abbreviations = new HashMap<>(); + AbbreviationCreator(AbbreviationVerifier abbreviationVerifier, HashMap abbreviations, + TextViewUtils textViewUtils) { + super(abbreviationVerifier); + this.abbreviations = abbreviations; this.textViewUtils = textViewUtils; } - AbbreviationCoordinator() { - this(new TextViewUtils()); + AbbreviationCreator(AbbreviationVerifier abbreviationVerifier) { + this(abbreviationVerifier, new HashMap(), new TextViewUtils()); + } + + AbbreviationCreator() { + this(new AbbreviationVerifier()); } /** @@ -39,7 +44,7 @@ class AbbreviationCoordinator { * @param bannerComponents object holding the abbreviation information * @param index in the list of BannerComponentNodes */ - void addPriorityInfo(BannerComponents bannerComponents, int index) { + private void addPriorityInfo(BannerComponents bannerComponents, int index) { Integer abbreviationPriority = bannerComponents.abbreviationPriority(); if (abbreviations.get(abbreviationPriority) == null) { abbreviations.put(abbreviationPriority, new ArrayList()); @@ -51,11 +56,12 @@ void addPriorityInfo(BannerComponents bannerComponents, int index) { * Using the abbreviations HashMap which should already be populated, abbreviates the text in the * bannerComponentNodes until the text fits the given TextView. * - * @param bannerComponentNodes containing the text to construct * @param textView to check the text fits + * @param bannerComponentNodes containing the text to construct * @return the properly abbreviated string that will fit in the TextView */ - String abbreviateBannerText(List bannerComponentNodes, TextView textView) { + private String abbreviateBannerText(TextView textView, List + bannerComponentNodes) { String bannerText = join(bannerComponentNodes); if (abbreviations.isEmpty()) { @@ -89,12 +95,15 @@ private String abbreviateUntilTextFits(TextView textView, String startingText, private boolean shouldKeepAbbreviating(TextView textView, String bannerText, int currAbbreviationPriority, int maxAbbreviationPriority) { - return !textViewUtils.textFits(textView, bannerText) && currAbbreviationPriority <= maxAbbreviationPriority; + + boolean textFits = textViewUtils.textFits(textView, bannerText); + boolean abbreviationPrioritiesLeft = currAbbreviationPriority <= maxAbbreviationPriority; + return !textFits && abbreviationPrioritiesLeft; } private boolean abbreviateAtAbbreviationPriority(List bannerComponentNodes, List indices) { - if (indices == null) { + if (indices == null || indices.isEmpty()) { return false; } @@ -130,11 +139,24 @@ private String join(List tokens) { return stringBuilder.toString(); } + @Override + AbbreviationNode setupNode(BannerComponents components, int index, int startIndex, String + modifier) { + addPriorityInfo(components, index); + return new AbbreviationCreator.AbbreviationNode(components, startIndex); + } + + @Override + void preProcess(TextView textView, List bannerComponentNodes) { + String text = abbreviateBannerText(textView, bannerComponentNodes); + textView.setText(text); + } + /** * Class used by InstructionLoader to determine that a BannerComponent contains an abbreviation */ static class AbbreviationNode extends BannerComponentNode { - boolean abbreviate; + private boolean abbreviate; AbbreviationNode(BannerComponents bannerComponents, int startIndex) { super(bannerComponents, startIndex); @@ -148,5 +170,9 @@ public String toString() { void setAbbreviate(boolean abbreviate) { this.abbreviate = abbreviate; } + + boolean getAbbreviate() { + return abbreviate; + } } } diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationVerifier.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationVerifier.java new file mode 100644 index 00000000000..fdb4217a040 --- /dev/null +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationVerifier.java @@ -0,0 +1,15 @@ +package com.mapbox.services.android.navigation.ui.v5.instruction; + +import com.mapbox.api.directions.v5.models.BannerComponents; +import com.mapbox.core.utils.TextUtils; + +class AbbreviationVerifier implements NodeVerifier { + @Override + public boolean isNodeType(BannerComponents bannerComponents) { + return hasAbbreviation(bannerComponents); + } + + private boolean hasAbbreviation(BannerComponents components) { + return !TextUtils.isEmpty(components.abbreviation()); + } +} diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentNode.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentNode.java new file mode 100644 index 00000000000..db671492fbf --- /dev/null +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentNode.java @@ -0,0 +1,25 @@ +package com.mapbox.services.android.navigation.ui.v5.instruction; + +import com.mapbox.api.directions.v5.models.BannerComponents; + +/** + * Class used to construct a list of BannerComponents to be populated into a TextView + */ +class BannerComponentNode { + BannerComponents bannerComponents; + int startIndex; + + BannerComponentNode(BannerComponents bannerComponents, int startIndex) { + this.bannerComponents = bannerComponents; + this.startIndex = startIndex; + } + + @Override + public String toString() { + return bannerComponents.text(); + } + + void setStartIndex(int startIndex) { + this.startIndex = startIndex; + } +} diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentTree.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentTree.java new file mode 100644 index 00000000000..4535daeebc5 --- /dev/null +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentTree.java @@ -0,0 +1,73 @@ +package com.mapbox.services.android.navigation.ui.v5.instruction; + +import android.support.annotation.NonNull; +import android.widget.TextView; + +import com.mapbox.api.directions.v5.models.BannerComponents; +import com.mapbox.api.directions.v5.models.BannerText; + +import java.util.ArrayList; +import java.util.List; + +class BannerComponentTree { + private final NodeCreator[] nodeCreators; + private final List bannerComponentNodes; + + /** + * Creates a master coordinator to make sure the coordinators passed in are used appropriately + * + * @param nodeCreators coordinators in the order that they should process banner components + */ + BannerComponentTree(@NonNull BannerText bannerText, NodeCreator... nodeCreators) { + this.nodeCreators = nodeCreators; + bannerComponentNodes = parseBannerComponents(bannerText); + } + + /** + * Parses the banner components and processes them using the nodeCreators in the order they + * were originally passed + * + * @param bannerText to parse + * @return the list of nodes representing the bannerComponents + */ + private List parseBannerComponents(BannerText bannerText) { + int length = 0; + List bannerComponentNodes = new ArrayList<>(); + + for (BannerComponents components : bannerText.components()) { + BannerComponentNode node = null; + for (NodeCreator nodeCreator : nodeCreators) { + if (nodeCreator.isNodeType(components)) { + node = nodeCreator.setupNode(components, bannerComponentNodes.size(), length, + bannerText.modifier()); + break; + } + } + + if (node != null) { + bannerComponentNodes.add(node); + length += components.text().length(); + } + } + + return bannerComponentNodes; + } + + /** + * Loads the instruction into the given text view. If things have to be done in a particular order, + * the coordinator methods preProcess and postProcess can be used. PreProcess should be used to + * load text into the textView (so there should only be one coordinator calling this method), and + * postProcess should be used to make changes to that text, i.e., to load images into the textView. + * + * @param textView in which to load text and images + */ + void loadInstruction(TextView textView) { + for (NodeCreator nodeCreator : nodeCreators) { + nodeCreator.preProcess(textView, bannerComponentNodes); + } + + for (NodeCreator nodeCreator : nodeCreators) { + nodeCreator.postProcess(textView, bannerComponentNodes); + } + } +} diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ExitSignCreator.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ExitSignCreator.java new file mode 100644 index 00000000000..b221f510d0a --- /dev/null +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ExitSignCreator.java @@ -0,0 +1,70 @@ +package com.mapbox.services.android.navigation.ui.v5.instruction; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.mapbox.api.directions.v5.models.BannerComponents; +import com.mapbox.services.android.navigation.ui.v5.R; + +import java.util.List; + +class ExitSignCreator extends NodeCreator { + private String exitNumber; + private int startIndex; + private TextViewUtils textViewUtils; + private String modifier; + private static final String EXIT = "exit"; + private static final String EXIT_NUMBER = "exit-number"; + private static final String LEFT = "left"; + + ExitSignCreator() { + super(new ExitSignVerifier()); + textViewUtils = new TextViewUtils(); + } + + @Override + BannerComponentNode setupNode(BannerComponents components, int index, int startIndex, + String modifier) { + if (components.type().equals(EXIT)) { + return null; + } else if (components.type().equals(EXIT_NUMBER)) { + exitNumber = components.text(); + this.startIndex = startIndex; + this.modifier = modifier; + } + + return new BannerComponentNode(components, startIndex); + } + + /** + * One coordinator should override this method, and this should be the coordinator which populates + * the textView with text. + * + * @param textView to populate + * @param bannerComponentNodes containing instructions + */ + @Override + void postProcess(TextView textView, List bannerComponentNodes) { + if (exitNumber != null) { + LayoutInflater inflater = (LayoutInflater) textView.getContext().getSystemService(Context + .LAYOUT_INFLATER_SERVICE); + + ViewGroup root = (ViewGroup) textView.getParent(); + + TextView exitSignView; + + if (modifier.equals(LEFT)) { + exitSignView = (TextView) inflater.inflate(R.layout.exit_sign_view_left, root, false); + } else { + exitSignView = (TextView) inflater.inflate(R.layout.exit_sign_view_right, root, false); + } + + exitSignView.setText(exitNumber); + + textViewUtils.setImageSpan(textView, exitSignView, startIndex, startIndex + exitNumber + .length()); + } + } +} diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ExitSignVerifier.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ExitSignVerifier.java new file mode 100644 index 00000000000..fb79f5939b4 --- /dev/null +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ExitSignVerifier.java @@ -0,0 +1,11 @@ +package com.mapbox.services.android.navigation.ui.v5.instruction; + +import com.mapbox.api.directions.v5.models.BannerComponents; + +class ExitSignVerifier implements NodeVerifier { + + @Override + public boolean isNodeType(BannerComponents bannerComponents) { + return bannerComponents.type().equals("exit") || bannerComponents.type().equals("exit-number"); + } +} diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ImageCoordinator.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ImageCreator.java similarity index 84% rename from libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ImageCoordinator.java rename to libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ImageCreator.java index 51ecda299c0..d78fffeb40b 100644 --- a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ImageCoordinator.java +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ImageCreator.java @@ -3,7 +3,6 @@ import android.content.Context; import android.text.Spannable; import android.text.SpannableString; -import android.text.TextUtils; import android.text.style.ImageSpan; import android.widget.TextView; @@ -11,7 +10,6 @@ import com.mapbox.api.directions.v5.models.BannerInstructions; import com.mapbox.api.directions.v5.models.BannerText; import com.mapbox.api.directions.v5.models.LegStep; -import com.mapbox.services.android.navigation.ui.v5.instruction.InstructionLoader.BannerComponentNode; import com.squareup.picasso.Picasso; import java.util.ArrayList; @@ -27,16 +25,35 @@ * If a shield URL is found, {@link Picasso} is used to load the image. Then, once the image is loaded, * a new {@link ImageSpan} is created and set to the appropriate position of the {@link Spannable} */ -public class ImageCoordinator { +public class ImageCreator extends NodeCreator { - private static ImageCoordinator instance; + private static ImageCreator instance; private boolean isInitialized; private Picasso picassoImageLoader; private List targets; private UrlDensityMap urlDensityMap; private List bannerShieldList; - private ImageCoordinator() { + private ImageCreator(ImageVerifier imageVerifier) { + super(imageVerifier); + } + + @Override + BannerComponentNode setupNode(BannerComponents components, int index, int startIndex, + String modifier) { + addShieldInfo(components, index); + return new BannerComponentNode(components, startIndex); + } + + /** + * Uses the given BannerComponents object to construct a BannerShield object containing the + * information needed to load the proper image into the TextView where appropriate. + * + * @param bannerComponents containing image info + * @param index of the BannerComponentNode which refers to the given BannerComponents + */ + private void addShieldInfo(BannerComponents bannerComponents, int index) { + bannerShieldList.add(new BannerShield(bannerComponents, index)); } /** @@ -44,9 +61,9 @@ private ImageCoordinator() { * * @return ImageCoordinator */ - public static synchronized ImageCoordinator getInstance() { + public static synchronized ImageCreator getInstance() { if (instance == null) { - instance = new ImageCoordinator(); + instance = new ImageCreator(new ImageVerifier()); } return instance; @@ -68,17 +85,6 @@ public void initialize(Context context) { } } - /** - * Uses the given BannerComponents object to construct a BannerShield object containing the - * information needed to load the proper image into the TextView where appropriate. - * - * @param bannerComponents containing image info - * @param index of the BannerComponentNode which refers to the given BannerComponents - */ - public void addShieldInfo(BannerComponents bannerComponents, int index) { - bannerShieldList.add(new BannerShield(bannerComponents, index)); - } - /** * Will pre-fetch images for a given {@link LegStep}. *

@@ -104,7 +110,7 @@ public void shutdown() { * @param textView target for the banner text * @since 0.9.0 */ - public void loadImages(TextView textView, List bannerComponentNodes) { + private void loadImages(TextView textView, List bannerComponentNodes) { if (!hasImages()) { return; } @@ -164,18 +170,15 @@ private boolean hasImages() { */ private void fetchImageBaseUrls(BannerText bannerText) { for (BannerComponents components : bannerText.components()) { - if (hasImageUrl(components)) { + if (nodeVerifier.hasImageUrl(components)) { picassoImageLoader.load(urlDensityMap.get(components.imageBaseUrl())).fetch(); } } } - private boolean hasImageUrl(BannerComponents components) { - return !TextUtils.isEmpty(components.imageBaseUrl()); - } - private void createTargets(TextView textView) { Spannable instructionSpannable = new SpannableString(textView.getText()); + for (final BannerShield bannerShield : bannerShieldList) { targets.add(new InstructionTarget(textView, instructionSpannable, bannerShieldList, bannerShield, new InstructionTarget.InstructionLoadedCallback() { @@ -197,14 +200,12 @@ private void loadTargets() { private void checkIsInitialized() { if (!isInitialized) { - throw new RuntimeException("ImageCoordinator must be initialized prior to loading image URLs"); + throw new RuntimeException("ImageCreator must be initialized prior to loading image URLs"); } } - static class ImageNode extends BannerComponentNode { - - ImageNode(BannerComponents bannerComponents, int startIndex) { - super(bannerComponents, startIndex); - } + @Override + void postProcess(TextView textView, List bannerComponentNodes) { + loadImages(textView, bannerComponentNodes); } } diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ImageVerifier.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ImageVerifier.java new file mode 100644 index 00000000000..a6002addb59 --- /dev/null +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/ImageVerifier.java @@ -0,0 +1,17 @@ +package com.mapbox.services.android.navigation.ui.v5.instruction; + +import android.text.TextUtils; + +import com.mapbox.api.directions.v5.models.BannerComponents; + +class ImageVerifier implements NodeVerifier { + + @Override + public boolean isNodeType(BannerComponents bannerComponents) { + return hasImageUrl(bannerComponents); + } + + boolean hasImageUrl(BannerComponents components) { + return !TextUtils.isEmpty(components.imageBaseUrl()); + } +} diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionLoader.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionLoader.java index c255e8a0523..6efb275ee30 100644 --- a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionLoader.java +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionLoader.java @@ -7,14 +7,8 @@ import com.mapbox.api.directions.v5.models.BannerComponents; import com.mapbox.api.directions.v5.models.BannerText; -import com.mapbox.core.utils.TextUtils; -import com.mapbox.services.android.navigation.ui.v5.instruction.AbbreviationCoordinator.AbbreviationNode; -import com.mapbox.services.android.navigation.ui.v5.instruction.ImageCoordinator.ImageNode; import com.squareup.picasso.Picasso; -import java.util.ArrayList; -import java.util.List; - /** * Utility class that can be used to load a given {@link BannerText} into the provided * {@link TextView}. @@ -26,10 +20,8 @@ * a new {@link ImageSpan} is created and set to the appropriate position of the {@link Spannable}/ */ public class InstructionLoader { - private ImageCoordinator imageCoordinator; - private AbbreviationCoordinator abbreviationCoordinator; private TextView textView; - private List bannerComponentNodes; + private BannerComponentTree bannerComponentTree; /** * Creates an InstructionLoader which can handle highway shields and also takes into account @@ -38,18 +30,14 @@ public class InstructionLoader { * @param textView to populate with instruction * @param bannerText containing components to populate into textView */ - public InstructionLoader(TextView textView, BannerText bannerText) { - this(textView, bannerText, ImageCoordinator.getInstance(), new AbbreviationCoordinator()); + public InstructionLoader(TextView textView, @NonNull BannerText bannerText) { + this(textView, new BannerComponentTree(bannerText, new ExitSignCreator(), + ImageCreator.getInstance(), new AbbreviationCreator(), new TextCreator())); } - InstructionLoader(TextView textView, @NonNull BannerText bannerText, - ImageCoordinator imageCoordinator, AbbreviationCoordinator abbreviationCoordinator) { - this.abbreviationCoordinator = abbreviationCoordinator; + InstructionLoader(TextView textView, BannerComponentTree bannerComponentTree) { this.textView = textView; - bannerComponentNodes = new ArrayList<>(); - this.imageCoordinator = imageCoordinator; - - bannerComponentNodes = parseBannerComponents(bannerText.components()); + this.bannerComponentTree = bannerComponentTree; } /** @@ -58,80 +46,6 @@ public InstructionLoader(TextView textView, BannerText bannerText) { * into the given {@link TextView}. */ public void loadInstruction() { - setText(textView, bannerComponentNodes); - loadImages(textView, bannerComponentNodes); - } - - private List parseBannerComponents(List bannerComponents) { - int length = 0; - bannerComponentNodes = new ArrayList<>(); - - for (BannerComponents components : bannerComponents) { - BannerComponentNode node; - if (hasImageUrl(components)) { - node = setupImageNode(components, bannerComponentNodes.size(), length - 1); - } else if (hasAbbreviation(components)) { - node = setupAbbreviationNode(components, bannerComponentNodes.size(), length - 1); - } else { - node = new BannerComponentNode(components, length - 1); - } - bannerComponentNodes.add(node); - length += components.text().length() + 1; - } - - return bannerComponentNodes; - } - - private ImageNode setupImageNode(BannerComponents components, int index, int startIndex) { - imageCoordinator.addShieldInfo(components, index); - return new ImageNode(components, startIndex); - } - - private AbbreviationNode setupAbbreviationNode(BannerComponents components, int index, int startIndex) { - abbreviationCoordinator.addPriorityInfo(components, index); - return new AbbreviationCoordinator.AbbreviationNode(components, startIndex); - } - - private void loadImages(TextView textView, List bannerComponentNodes) { - imageCoordinator.loadImages(textView, bannerComponentNodes); - } - - private void setText(TextView textView, List bannerComponentNodes) { - String text = getAbbreviatedBannerText(textView, bannerComponentNodes); - textView.setText(text); - } - - private String getAbbreviatedBannerText(TextView textView, List bannerComponentNodes) { - return abbreviationCoordinator.abbreviateBannerText(bannerComponentNodes, textView); - } - - private boolean hasAbbreviation(BannerComponents components) { - return !TextUtils.isEmpty(components.abbreviation()); - } - - private boolean hasImageUrl(BannerComponents components) { - return !TextUtils.isEmpty(components.imageBaseUrl()); - } - - /** - * Class used to construct a list of BannerComponents to be populated into a TextView - */ - static class BannerComponentNode { - BannerComponents bannerComponents; - int startIndex; - - BannerComponentNode(BannerComponents bannerComponents, int startIndex) { - this.bannerComponents = bannerComponents; - this.startIndex = startIndex; - } - - @Override - public String toString() { - return bannerComponents.text(); - } - - public void setStartIndex(int startIndex) { - this.startIndex = startIndex; - } + bannerComponentTree.loadInstruction(textView); } } diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionTarget.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionTarget.java index 3a51c4af005..9539fc8e50a 100644 --- a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionTarget.java +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionTarget.java @@ -1,7 +1,6 @@ package com.mapbox.services.android.navigation.ui.v5.instruction; import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.text.Spannable; import android.text.Spanned; @@ -23,15 +22,22 @@ public class InstructionTarget implements Target { private List shields; private BannerShield shield; private InstructionLoadedCallback instructionLoadedCallback; + private TextViewUtils textViewUtils; - InstructionTarget(TextView textView, Spannable instructionSpannable, - List shields, BannerShield shield, - InstructionLoadedCallback instructionLoadedCallback) { + InstructionTarget(TextView textView, Spannable instructionSpannable, List shields, + BannerShield shield, InstructionLoadedCallback instructionLoadedCallback) { + this(textView, instructionSpannable, shields, shield, new TextViewUtils(), instructionLoadedCallback); + } + + private InstructionTarget(TextView textView, Spannable instructionSpannable, List shields, + BannerShield shield, TextViewUtils textViewUtils, + InstructionLoadedCallback instructionLoadedCallback) { this.textView = textView; this.instructionSpannable = instructionSpannable; this.shields = shields; this.shield = shield; this.instructionLoadedCallback = instructionLoadedCallback; + this.textViewUtils = textViewUtils; } BannerShield getShield() { @@ -40,7 +46,7 @@ BannerShield getShield() { @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { - Drawable drawable = createDrawable(bitmap); + Drawable drawable = textViewUtils.createDrawable(textView, bitmap); createAndSetImageSpan(drawable); sendInstructionLoadedCallback(); } @@ -75,14 +81,6 @@ private void createAndSetImageSpan(Drawable drawable) { } } - private Drawable createDrawable(Bitmap bitmap) { - Drawable drawable = new BitmapDrawable(textView.getContext().getResources(), bitmap); - int bottom = textView.getLineHeight(); - int right = bottom * bitmap.getWidth() / bitmap.getHeight(); - drawable.setBounds(0, 0, right, bottom); - return drawable; - } - private void sendInstructionLoadedCallback() { if (instructionLoadedCallback != null) { instructionLoadedCallback.onInstructionLoaded(this); diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionView.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionView.java index 7c7f5203f0c..64e9442bc8d 100644 --- a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionView.java +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionView.java @@ -141,7 +141,7 @@ protected void onFinishInflate() { initializeAnimations(); initializeStepListClickListener(); initializeButtons(); - ImageCoordinator.getInstance().initialize(getContext()); + ImageCreator.getInstance().initialize(getContext()); } @Override @@ -314,14 +314,17 @@ public boolean isShowingInstructionList() { public void hideInstructionList() { rvInstructions.stopScroll(); beginDelayedTransition(); - int orientation = getContext().getResources().getConfiguration().orientation; - if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + if (isLandscape()) { updateLandscapeConstraintsTo(R.layout.instruction_layout); } instructionListLayout.setVisibility(GONE); onInstructionListVisibilityChanged(false); } + private boolean isLandscape() { + return getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; + } + /** * Show the instruction list. *

@@ -332,8 +335,7 @@ public void showInstructionList() { onInstructionListVisibilityChanged(true); instructionLayout.requestFocus(); beginDelayedListTransition(); - int orientation = getContext().getResources().getConfiguration().orientation; - if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + if (isLandscape()) { updateLandscapeConstraintsTo(R.layout.instruction_layout_alt); } instructionListLayout.setVisibility(VISIBLE); @@ -435,7 +437,7 @@ private void initializeBackground() { int navigationViewListBackgroundColor = ThemeSwitcher.retrieveThemeColor(getContext(), R.attr.navigationViewListBackground); // Instruction Layout landscape - banner background - if (getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + if (isLandscape()) { View instructionLayoutManeuver = findViewById(R.id.instructionManeuverLayout); Drawable maneuverBackground = DrawableCompat.wrap(instructionLayoutManeuver.getBackground()).mutate(); DrawableCompat.setTint(maneuverBackground, navigationViewBannerBackgroundColor); @@ -525,9 +527,7 @@ private void showButtons() { } private void initializeStepListClickListener() { - int deviceOrientation = getContext().getResources().getConfiguration().orientation; - boolean isOrientationLandscape = deviceOrientation == Configuration.ORIENTATION_LANDSCAPE; - if (isOrientationLandscape) { + if (isLandscape()) { initializeLandscapeListListener(); } else { initializePortraitListListener(); @@ -596,7 +596,8 @@ private void distanceText(InstructionModel model) { upcomingDistanceText.setText(model.retrieveStepDistanceRemaining()); } - private InstructionLoader createInstructionLoader(TextView textView, BannerText bannerText) { + private InstructionLoader createInstructionLoader(TextView textView, BannerText + bannerText) { if (hasComponents(bannerText)) { return new InstructionLoader(textView, bannerText); } else { @@ -654,7 +655,7 @@ private boolean shouldShowSubStep(@Nullable BannerText subText) { } private void showSubLayout() { - if (subStepLayout.getVisibility() == GONE) { + if (!(subStepLayout.getVisibility() == VISIBLE)) { beginDelayedTransition(); subStepLayout.setVisibility(VISIBLE); } @@ -709,8 +710,7 @@ private FragmentManager obtainSupportFragmentManager() { * @param percentBias to be set to the text layout */ private void adjustBannerTextVerticalBias(float percentBias) { - int orientation = getContext().getResources().getConfiguration().orientation; - if (orientation == Configuration.ORIENTATION_PORTRAIT) { + if (!isLandscape()) { ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) instructionLayoutText.getLayoutParams(); params.verticalBias = percentBias; instructionLayoutText.setLayoutParams(params); @@ -738,7 +738,7 @@ private void updateDataFromInstruction(InstructionModel model) { updateInstructionList(model); if (newStep(model.retrieveProgress())) { LegStep upComingStep = model.retrieveProgress().currentLegProgress().upComingStep(); - ImageCoordinator.getInstance().prefetchImageCache(upComingStep); + ImageCreator.getInstance().prefetchImageCache(upComingStep); } } @@ -766,6 +766,7 @@ private void loadPrimaryAndSecondary(BannerText primaryBannerText, BannerText se upcomingSecondaryText.setVisibility(VISIBLE); adjustBannerTextVerticalBias(0.65f); loadTextWith(primaryBannerText, upcomingPrimaryText); + loadTextWith(secondaryBannerText, upcomingSecondaryText); } diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/NodeCreator.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/NodeCreator.java new file mode 100644 index 00000000000..68bd65906b1 --- /dev/null +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/NodeCreator.java @@ -0,0 +1,39 @@ +package com.mapbox.services.android.navigation.ui.v5.instruction; + +import android.widget.TextView; + +import com.mapbox.api.directions.v5.models.BannerComponents; + +import java.util.List; + +abstract class NodeCreator { + V nodeVerifier; + + NodeCreator(V nodeVerifier) { + this.nodeVerifier = nodeVerifier; + } + + boolean isNodeType(BannerComponents bannerComponents) { + return nodeVerifier.isNodeType(bannerComponents); + } + + abstract N setupNode(BannerComponents components, int index, int startIndex, String modifier); + + /** + * One coordinator should override this method, and this should be the coordinator which populates + * the textView with text. + * + * @param textView to populate + * @param bannerComponentNodes containing instructions + */ + void preProcess(TextView textView, List bannerComponentNodes) {} + + /** + * Coordinators which make edits to the text after it's been populated into the text view should + * override this method. This includes coordinators which load images into the text view. + * + * @param textView to populate + * @param bannerComponentNodes containing instructions + */ + void postProcess(TextView textView, List bannerComponentNodes) {} +} diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/NodeVerifier.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/NodeVerifier.java new file mode 100644 index 00000000000..a6401658cce --- /dev/null +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/NodeVerifier.java @@ -0,0 +1,7 @@ +package com.mapbox.services.android.navigation.ui.v5.instruction; + +import com.mapbox.api.directions.v5.models.BannerComponents; + +interface NodeVerifier { + boolean isNodeType(BannerComponents bannerComponents); +} diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/TextCreator.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/TextCreator.java new file mode 100644 index 00000000000..299b7530396 --- /dev/null +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/TextCreator.java @@ -0,0 +1,22 @@ +package com.mapbox.services.android.navigation.ui.v5.instruction; + +import com.mapbox.api.directions.v5.models.BannerComponents; + +/** + * This is the default text coordinator implementation to handle plain text components. + */ +class TextCreator extends NodeCreator { + TextCreator() { + this(new TextVerifier()); + } + + private TextCreator(TextVerifier textVerifier) { + super(textVerifier); + } + + @Override + BannerComponentNode setupNode(BannerComponents components, int index, int startIndex, String + modifier) { + return new BannerComponentNode(components, startIndex); + } +} diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/TextVerifier.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/TextVerifier.java new file mode 100644 index 00000000000..b0040b78cb2 --- /dev/null +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/TextVerifier.java @@ -0,0 +1,10 @@ +package com.mapbox.services.android.navigation.ui.v5.instruction; + +import com.mapbox.api.directions.v5.models.BannerComponents; + +class TextVerifier implements NodeVerifier { + @Override + public boolean isNodeType(BannerComponents bannerComponents) { + return bannerComponents.text() != null && !bannerComponents.text().isEmpty(); + } +} diff --git a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/TextViewUtils.java b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/TextViewUtils.java index fb5665be7aa..a8ba92b521e 100644 --- a/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/TextViewUtils.java +++ b/libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/instruction/TextViewUtils.java @@ -1,6 +1,16 @@ package com.mapbox.services.android.navigation.ui.v5.instruction; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.ImageSpan; +import android.view.View; import android.widget.TextView; class TextViewUtils { @@ -10,4 +20,47 @@ boolean textFits(TextView textView, String text) { float width = paint.measureText(text); return width < textView.getWidth(); } + + Drawable createDrawable(TextView textView, Bitmap bitmap) { + Drawable drawable = new BitmapDrawable(textView.getContext().getResources(), bitmap); + int bottom = textView.getLineHeight(); + int right = bottom * bitmap.getWidth() / bitmap.getHeight(); + drawable.setBounds(0, 0, right, bottom); + + return drawable; + } + + void setImageSpan(TextView textView, View view, int start, int end) { + Bitmap bitmap = createBitmapFromView(view); + setImageSpan(textView, bitmap, start, end); + } + + private void setImageSpan(TextView textView, Bitmap bitmap, int start, int end) { + Drawable drawable = createDrawable(textView, bitmap); + setImageSpan(textView, drawable, start, end); + } + + private void setImageSpan(TextView textView, Drawable drawable, int start, int end) { + Spannable instructionSpannable = new SpannableString(textView.getText()); + + instructionSpannable.setSpan(new ImageSpan(drawable), + start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + textView.setText(instructionSpannable); + } + + private Bitmap createBitmapFromView(View view) { + int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + view.measure(measureSpec, measureSpec); + + int measuredWidth = view.getMeasuredWidth(); + int measuredHeight = view.getMeasuredHeight(); + + view.layout(0, 0, measuredWidth, measuredHeight); + Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888); + bitmap.eraseColor(Color.TRANSPARENT); + Canvas canvas = new Canvas(bitmap); + view.draw(canvas); + return bitmap; + } } diff --git a/libandroid-navigation-ui/src/main/res/drawable/ic_exit_arrow_left.xml b/libandroid-navigation-ui/src/main/res/drawable/ic_exit_arrow_left.xml new file mode 100644 index 00000000000..c5a49d8e23a --- /dev/null +++ b/libandroid-navigation-ui/src/main/res/drawable/ic_exit_arrow_left.xml @@ -0,0 +1,11 @@ + + + + diff --git a/libandroid-navigation-ui/src/main/res/drawable/ic_exit_arrow_right.xml b/libandroid-navigation-ui/src/main/res/drawable/ic_exit_arrow_right.xml new file mode 100644 index 00000000000..1c4729f8ee5 --- /dev/null +++ b/libandroid-navigation-ui/src/main/res/drawable/ic_exit_arrow_right.xml @@ -0,0 +1,11 @@ + + + + diff --git a/libandroid-navigation-ui/src/main/res/drawable/rounded_corners.xml b/libandroid-navigation-ui/src/main/res/drawable/rounded_corners.xml new file mode 100644 index 00000000000..039b43c1f37 --- /dev/null +++ b/libandroid-navigation-ui/src/main/res/drawable/rounded_corners.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/libandroid-navigation-ui/src/main/res/layout/exit_sign_view_left.xml b/libandroid-navigation-ui/src/main/res/layout/exit_sign_view_left.xml new file mode 100644 index 00000000000..ff3f8be0838 --- /dev/null +++ b/libandroid-navigation-ui/src/main/res/layout/exit_sign_view_left.xml @@ -0,0 +1,18 @@ + + diff --git a/libandroid-navigation-ui/src/main/res/layout/exit_sign_view_right.xml b/libandroid-navigation-ui/src/main/res/layout/exit_sign_view_right.xml new file mode 100644 index 00000000000..1f11cf19adc --- /dev/null +++ b/libandroid-navigation-ui/src/main/res/layout/exit_sign_view_right.xml @@ -0,0 +1,18 @@ + + diff --git a/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationCoordinatorTest.java b/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationCoordinatorTest.java deleted file mode 100644 index ece3f95acd5..00000000000 --- a/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationCoordinatorTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.mapbox.services.android.navigation.ui.v5.instruction; - -import android.widget.TextView; - -import com.mapbox.api.directions.v5.models.BannerComponents; -import com.mapbox.services.android.navigation.ui.v5.BaseTest; - -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class AbbreviationCoordinatorTest extends BaseTest { - @Test - public void onAbbreviateBannerText_textIsAbbreviated() { - String abbreviation = "smtxt"; - BannerComponents bannerComponents = - BannerComponentsFaker.bannerComponents() - .abbreviation(abbreviation) - .abbreviationPriority(0) - .build(); - TextViewUtils textViewUtils = mock(TextViewUtils.class); - TextView textView = mock(TextView.class); - when(textViewUtils.textFits(textView, abbreviation)).thenReturn(true); - when(textViewUtils.textFits(textView, bannerComponents.text())).thenReturn(false); - AbbreviationCoordinator abbreviationCoordinator = new AbbreviationCoordinator(textViewUtils); - abbreviationCoordinator.addPriorityInfo(bannerComponents, 0); - List bannerComponentNodes = new ArrayList<>(); - bannerComponentNodes.add(new AbbreviationCoordinator.AbbreviationNode(bannerComponents, 0)); - - String abbreviatedTextFromCoordinator = abbreviationCoordinator.abbreviateBannerText(bannerComponentNodes, textView); - - assertEquals(abbreviation, abbreviatedTextFromCoordinator); - } - - @Test - public void onAbbreviateBannerText_textIsNotAbbreviated() { - String abbreviation = "smtxt"; - String text = "some text"; - BannerComponents bannerComponents = - BannerComponentsFaker.bannerComponents() - .abbreviation(abbreviation) - .abbreviationPriority(0) - .text(text) - .build(); - TextViewUtils textViewUtils = mock(TextViewUtils.class); - TextView textView = mock(TextView.class); - when(textViewUtils.textFits(textView, bannerComponents.text())).thenReturn(true); - AbbreviationCoordinator abbreviationCoordinator = new AbbreviationCoordinator(textViewUtils); - abbreviationCoordinator.addPriorityInfo(bannerComponents, 0); - List bannerComponentNodes = new ArrayList<>(); - bannerComponentNodes.add(new AbbreviationCoordinator.AbbreviationNode(bannerComponents, 0)); - - String abbreviatedTextFromCoordinator = abbreviationCoordinator.abbreviateBannerText(bannerComponentNodes, textView); - - assertEquals(text, abbreviatedTextFromCoordinator); - } -} diff --git a/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationCreatorTest.java b/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationCreatorTest.java new file mode 100644 index 00000000000..4757d01ce82 --- /dev/null +++ b/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/AbbreviationCreatorTest.java @@ -0,0 +1,68 @@ +package com.mapbox.services.android.navigation.ui.v5.instruction; + +import android.widget.TextView; + +import com.mapbox.api.directions.v5.models.BannerComponents; +import com.mapbox.services.android.navigation.ui.v5.BaseTest; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class AbbreviationCreatorTest extends BaseTest { + + @Test + public void preProcess_abbreviate() { + String abbreviation = "smtxt"; + BannerComponents bannerComponents = + BannerComponentsFaker.bannerComponentsBuilder() + .abbreviation(abbreviation) + .abbreviationPriority(0) + .build(); + TextView textView = mock(TextView.class); + AbbreviationVerifier abbreviationVerifier = mock(AbbreviationVerifier.class); + when(abbreviationVerifier.isNodeType(bannerComponents)).thenReturn(true); + TextViewUtils textViewUtils = mock(TextViewUtils.class); + when(textViewUtils.textFits(textView, abbreviation)).thenReturn(true); + when(textViewUtils.textFits(textView, bannerComponents.text())).thenReturn(false); + BannerComponentNode node = mock(AbbreviationCreator.AbbreviationNode.class); + when(((AbbreviationCreator.AbbreviationNode) node).getAbbreviate()).thenReturn(true); + when(node.toString()).thenReturn(abbreviation); + AbbreviationCreator abbreviationCreator = new AbbreviationCreator(abbreviationVerifier); + + abbreviationCreator.preProcess(textView, Collections.singletonList(node)); + + verify(textView).setText(abbreviation); + } + + @Test + public void setupNode() { + String abbreviation = "smtxt"; + int abbreviationPriority = 0; + BannerComponents bannerComponents = + BannerComponentsFaker.bannerComponentsBuilder() + .abbreviation(abbreviation) + .abbreviationPriority(abbreviationPriority) + .build(); + AbbreviationVerifier abbreviationVerifier = mock(AbbreviationVerifier.class); + when(abbreviationVerifier.isNodeType(bannerComponents)).thenReturn(true); + HashMap> abbreviations = new HashMap(); + AbbreviationCreator abbreviationCreator = new AbbreviationCreator(abbreviationVerifier, + abbreviations, mock(TextViewUtils.class)); + List bannerComponentNodes = new ArrayList<>(); + bannerComponentNodes.add(new AbbreviationCreator.AbbreviationNode(bannerComponents, 0)); + + abbreviationCreator.setupNode(bannerComponents, 0, 0, ""); + + assertEquals(abbreviations.size(), 1); + assertEquals(abbreviations.get(abbreviationPriority).get(0), Integer.valueOf(0)); + } +} diff --git a/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentTreeTest.java b/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentTreeTest.java new file mode 100644 index 00000000000..4373d9e31e7 --- /dev/null +++ b/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentTreeTest.java @@ -0,0 +1,81 @@ +package com.mapbox.services.android.navigation.ui.v5.instruction; + +import android.widget.TextView; + +import com.mapbox.api.directions.v5.models.BannerComponents; +import com.mapbox.api.directions.v5.models.BannerText; + +import org.junit.Test; +import org.mockito.InOrder; + +import java.util.Collections; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + + +public class BannerComponentTreeTest { + + @Test + public void parseComponents() { + BannerComponents bannerComponents = BannerComponentsFaker.bannerComponents(); + List bannerComponentsList = Collections.singletonList(bannerComponents); + TestCreator testCreator = mock(TestCreator.class); + when(testCreator.isNodeType(bannerComponents)).thenReturn(true); + BannerText bannerText = mock(BannerText.class); + when(bannerText.components()).thenReturn(bannerComponentsList); + + new BannerComponentTree(bannerText, testCreator); + + verify(testCreator).setupNode(bannerComponents, 0, 0, null); + } + + @Test + public void loadInstruction() { + BannerComponents bannerComponents = BannerComponentsFaker.bannerComponents(); + List bannerComponentsList = Collections.singletonList(bannerComponents); + TestNode testNode = mock(TestNode.class); + TestCreator testCreator = mock(TestCreator.class); + when(testCreator.isNodeType(bannerComponents)).thenReturn(true); + when(testCreator.setupNode(bannerComponents, 0, 0, null)).thenReturn(testNode); + TextView textView = mock(TextView.class); + BannerText bannerText = mock(BannerText.class); + when(bannerText.components()).thenReturn(bannerComponentsList); + BannerComponentTree bannerComponentTree = new BannerComponentTree(bannerText, testCreator); + + bannerComponentTree.loadInstruction(textView); + + InOrder inOrder = inOrder(testCreator, testCreator); + inOrder.verify(testCreator).preProcess(any(TextView.class), any(List.class)); + inOrder.verify(testCreator).postProcess(any(TextView.class), any(List.class)); + } + + class TestNode extends BannerComponentNode { + TestNode(BannerComponents bannerComponents, int startIndex) { + super(bannerComponents, startIndex); + } + } + + class TestVerifier implements NodeVerifier { + + @Override + public boolean isNodeType(BannerComponents bannerComponents) { + return true; + } + } + + class TestCreator extends NodeCreator { + TestCreator(TestVerifier nodeVerifier) { + super(nodeVerifier); + } + + @Override + TestNode setupNode(BannerComponents components, int index, int startIndex, String modifier) { + return new TestNode(components, startIndex); + } + } +} diff --git a/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentsFaker.java b/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentsFaker.java index 79096670d8b..f93f8e51362 100644 --- a/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentsFaker.java +++ b/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/BannerComponentsFaker.java @@ -3,9 +3,20 @@ import com.mapbox.api.directions.v5.models.BannerComponents; class BannerComponentsFaker { - static BannerComponents.Builder bannerComponents() { + static BannerComponents bannerComponents() { + return bannerComponentsBuilder().build(); + } + + static BannerComponents.Builder bannerComponentsBuilder() { return BannerComponents.builder() .type("some type") .text("some text"); } + + static BannerComponents bannerComponentsWithAbbreviation() { + return bannerComponentsBuilder() + .abbreviationPriority(1) + .abbreviation("abbreviation text") + .build(); + } } diff --git a/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionLoaderTest.java b/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionLoaderTest.java index 6b105618a77..37afd855c07 100644 --- a/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionLoaderTest.java +++ b/libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/instruction/InstructionLoaderTest.java @@ -2,100 +2,21 @@ import android.widget.TextView; -import com.mapbox.api.directions.v5.models.BannerComponents; -import com.mapbox.api.directions.v5.models.BannerText; - import org.junit.Test; -import java.util.ArrayList; -import java.util.List; - -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; public class InstructionLoaderTest { @Test - public void onInstructionLoaderCreated_priorityInfoIsAdded() { - TextView textView = mock(TextView.class); - ImageCoordinator imageCoordinator = mock(ImageCoordinator.class); - AbbreviationCoordinator abbreviationCoordinator = mock(AbbreviationCoordinator.class); - BannerComponents bannerComponents = BannerComponentsFaker.bannerComponents() - .abbreviationPriority(1) - .abbreviation("abbreviation text") - .build(); - List bannerComponentsList = new ArrayList<>(); - bannerComponentsList.add(bannerComponents); - BannerText bannerText = mock(BannerText.class); - when(bannerText.components()).thenReturn(bannerComponentsList); - - new InstructionLoader(textView, bannerText, imageCoordinator, abbreviationCoordinator); - - verify(abbreviationCoordinator).addPriorityInfo(bannerComponents, 0); - } - - @Test - public void onInstructionLoaderCreated_shieldInfoIsAdded() { - TextView textView = mock(TextView.class); - ImageCoordinator imageCoordinator = mock(ImageCoordinator.class); - AbbreviationCoordinator abbreviationCoordinator = mock(AbbreviationCoordinator.class); - BannerComponents bannerComponents = BannerComponentsFaker.bannerComponents() - .imageBaseUrl("string url") - .build(); - List bannerComponentsList = new ArrayList<>(); - bannerComponentsList.add(bannerComponents); - BannerText bannerText = mock(BannerText.class); - when(bannerText.components()).thenReturn(bannerComponentsList); - - new InstructionLoader(textView, bannerText, imageCoordinator, abbreviationCoordinator); - - verify(imageCoordinator).addShieldInfo(bannerComponents, 0); - } - - @Test - public void onLoadInstruction_textIsAbbreviated() { - TextView textView = mock(TextView.class); - ImageCoordinator imageCoordinator = mock(ImageCoordinator.class); - AbbreviationCoordinator abbreviationCoordinator = mock(AbbreviationCoordinator.class); - BannerComponents bannerComponents = BannerComponentsFaker.bannerComponents() - .abbreviationPriority(1) - .abbreviation("abbrv text") - .build(); - List bannerComponentsList = new ArrayList<>(); - bannerComponentsList.add(bannerComponents); - String abbreviatedText = "abbreviated text"; - when(abbreviationCoordinator.abbreviateBannerText(any(List.class), any(TextView.class))).thenReturn(abbreviatedText); - BannerText bannerText = mock(BannerText.class); - when(bannerText.components()).thenReturn(bannerComponentsList); - InstructionLoader instructionLoader = new InstructionLoader(textView, bannerText, imageCoordinator, - abbreviationCoordinator); - - instructionLoader.loadInstruction(); - - verify(textView).setText(abbreviatedText); - } - - @Test - public void onLoadInstruction_imagesAreLoaded() { + public void loadInstruction() { TextView textView = mock(TextView.class); - ImageCoordinator imageCoordinator = mock(ImageCoordinator.class); - AbbreviationCoordinator abbreviationCoordinator = mock(AbbreviationCoordinator.class); - BannerComponents bannerComponents = BannerComponentsFaker.bannerComponents() - .imageBaseUrl("string url") - .build(); - List bannerComponentsList = new ArrayList<>(); - bannerComponentsList.add(bannerComponents); - String abbreviatedText = "abbreviated text"; - when(abbreviationCoordinator.abbreviateBannerText(any(List.class), any(TextView.class))).thenReturn(abbreviatedText); - BannerText bannerText = mock(BannerText.class); - when(bannerText.components()).thenReturn(bannerComponentsList); - InstructionLoader instructionLoader = new InstructionLoader(textView, bannerText, imageCoordinator, - abbreviationCoordinator); + BannerComponentTree bannerComponentTree = mock(BannerComponentTree.class); + InstructionLoader instructionLoader = new InstructionLoader(textView, bannerComponentTree); instructionLoader.loadInstruction(); - verify(imageCoordinator).loadImages(any(TextView.class), any(List.class)); + verify(bannerComponentTree).loadInstruction(textView); } } \ No newline at end of file