public void renderElementAndPerformFallback()

in source/android/adaptivecards/src/main/java/io/adaptivecards/renderer/registration/CardRendererRegistration.java [284:453]


    public void renderElementAndPerformFallback(
            RenderedAdaptiveCard renderedCard,
            Context context,
            FragmentManager fragmentManager,
            BaseCardElement cardElement,
            ViewGroup viewGroup,
            ICardActionHandler cardActionHandler,
            HostConfig hostConfig,
            RenderArgs renderArgs,
            FeatureRegistration featureRegistration) throws AdaptiveFallbackException, Exception
    {
        IBaseCardElementRenderer renderer = m_typeToRendererMap.get(cardElement.GetElementTypeString());

        boolean elementHasFallback = (cardElement.GetFallbackType() != FallbackType.None);
        RenderArgs childRenderArgs = new RenderArgs(renderArgs);
        childRenderArgs.setAncestorHasFallback(elementHasFallback || renderArgs.getAncestorHasFallback());

        // To avoid tampering with this method, this two variables are introduced:
        // - renderedElement contains the element that was finally rendered (after performing fallback)
        //      this allows us to check if it was an input and render the label and error message
        BaseCardElement renderedElement = null;
        View renderedElementView = null;

        // - mockLayout is a layout to contain the rendered element, as android renderers have to add
        //      the drawn views into the container view, it makes it easier to do not draw something unwanted
        //      into the final rendered card
        ViewGroup mockLayout = null;
        if (Util.isOfType(cardElement, Column.class))
        {
            mockLayout = new FlexboxLayout(context);
        }
        else
        {
            mockLayout = new LinearLayout(context);
        }

        try
        {
            if (renderer == null)
            {
                throw new AdaptiveFallbackException(cardElement);
            }

            if ((featureRegistration != null) && (!cardElement.MeetsRequirements(featureRegistration)))
            {
                throw new AdaptiveFallbackException(cardElement, featureRegistration);
            }

            if (cardElement.GetElementType() == CardElementType.ActionSet)
            {
                renderArgs.setRootLevelActions(false);
            }

            renderedElementView = renderer.render(renderedCard, context, fragmentManager, mockLayout, cardElement, cardActionHandler, hostConfig, childRenderArgs);
            renderedElement = cardElement;
        }
        catch (AdaptiveFallbackException e)
        {
            if (elementHasFallback)
            {
                if (cardElement.GetFallbackType() == FallbackType.Content)
                {
                    BaseElement fallbackElement = cardElement.GetFallbackContent();
                    while (fallbackElement != null)
                    {
                        // Try to render the fallback element
                        try
                        {
                            BaseCardElement fallbackCardElement = Util.castToBaseCardElement(fallbackElement);
                            IBaseCardElementRenderer fallbackRenderer = m_typeToRendererMap.get(fallbackElement.GetElementTypeString());

                            if (fallbackRenderer == null)
                            {
                                throw new AdaptiveFallbackException(fallbackCardElement);
                            }

                            if ((featureRegistration != null) && (!fallbackElement.MeetsRequirements(featureRegistration)))
                            {
                                throw new AdaptiveFallbackException(fallbackCardElement, featureRegistration);
                            }

                            renderedCard.addWarning(new AdaptiveWarning(AdaptiveWarning.UNKNOWN_ELEMENT_TYPE,
                                                                        "Performing fallback for '" + cardElement.GetElementTypeString() +
                                                                            "' (fallback element type: '" + fallbackCardElement.GetElementTypeString() + "')"));

                            // before rendering, check if the element to render is an input, if it is, then create an stretchable input layout, and add the label
                            // pass that as the viewgroup and

                            renderedElementView = fallbackRenderer.render(renderedCard, context, fragmentManager, mockLayout, fallbackCardElement, cardActionHandler, hostConfig, childRenderArgs);
                            renderedElement = fallbackCardElement;
                            break;
                        }
                        catch (AdaptiveFallbackException e2)
                        {
                            // As the fallback element didn't exist, go back to trying
                            if (fallbackElement.GetFallbackType() == FallbackType.Content)
                            {
                                fallbackElement = fallbackElement.GetFallbackContent();
                            }
                            else
                            {
                                // The element has no fallback, just clear the element so the cycle ends
                                fallbackElement = null;
                            }

                            renderedElement = null;
                        }
                    }
                }
                else if (cardElement.GetFallbackType() == FallbackType.Drop)
                {
                    renderedCard.addWarning(new AdaptiveWarning(AdaptiveWarning.UNKNOWN_ELEMENT_TYPE,
                                                                "Dropping element '" + cardElement.GetElementTypeString() + "' for fallback"));

                    renderedElement = null;
                }
            }
            else if (renderArgs.getAncestorHasFallback())
            {
                // There's an ancestor with fallback so we throw to trigger it
                throw e;
            }
            else
            {
                // The element doesn't have a fallback, so the element can't be rendered and it's dropped
                renderedCard.addWarning(new AdaptiveWarning(AdaptiveWarning.UNKNOWN_ELEMENT_TYPE, "Unsupported card element type: " + cardElement.GetElementTypeString()));
                renderedElement = null;
            }
        }

        if (renderedElement != null && renderedElementView != null)
        {

            View taggedView = findElementWithTagContent(mockLayout);
            TagContent tagContent = BaseCardElementRenderer.getTagContent(taggedView);

            // Sets this view container as the element is being moved to the correct location
            tagContent.SetViewContainer(viewGroup);

            // Render the spacing so no other renderers have to do it
            boolean isColumn = Util.isOfType(renderedElement, Column.class);

            // Only columns render vertical spacing, so if it's not a column, then we need a horizontal spacing
            HandleSpacing(context, viewGroup, renderedElement, hostConfig, tagContent, !isColumn);

            // Check if the element is an input or must be stretched
            BaseInputElement baseInputElement = Util.tryCastTo(renderedElement, BaseInputElement.class);
            if (baseInputElement != null)
            {
                // put the element in a Stretchable input layout and
                HandleLabelAndValidation(renderedCard, mockLayout, viewGroup, baseInputElement, context, hostConfig, renderArgs, tagContent);
            }
            else
            {
                // Column, container, image and imageSet handle their height on their own, so let's not add an extra view for them
                if (renderedElement.GetHeight() == HeightType.Stretch && !isColumn && !Util.isOfType(renderedElement, Container.class)
                    && !Util.isOfType(renderedElement, Image.class) && !Util.isOfType(renderedElement, ImageSet.class))
                {
                    // put the element in a StretchableElementLayout
                    HandleStretchHeight(mockLayout, viewGroup, renderedElement, context, tagContent);
                }
                else
                {
                    Util.MoveChildrenViews(mockLayout, viewGroup);
                }
            }

            HandleVisibility(renderedElement, renderedElementView);
        }
    }