platform/android/library/src/in/uncod/android/bypass/Bypass.java
private CharSequence recurseElement(Element element, int indexWithinParent, int numberOfSiblings,
			ImageGetter imageGetter) {

		Type type = element.getType();

		boolean isOrderedList = false;
		if (type == Type.LIST) {
			String flagsStr = element.getAttribute("flags");
			if (flagsStr != null) {
				int flags = Integer.parseInt(flagsStr);
				isOrderedList = (flags & Element.F_LIST_ORDERED) != 0;
				if (isOrderedList) {
					mOrderedListNumber.put(element, 1);
				}
			}
		}

		int size = element.size();
		CharSequence[] spans = new CharSequence[size];
		
		for (int i = 0; i < size; i++) {
			spans[i] = recurseElement(element.children[i], i, size, imageGetter);
		}

		// Clean up after we're done
		if (isOrderedList) {
			mOrderedListNumber.remove(this);
		}

		CharSequence concat = TextUtils.concat(spans);

		SpannableStringBuilder builder = new ReverseSpannableStringBuilder();

		String text = element.getText();
		if (element.size() == 0
			&& element.getParent() != null
			&& element.getParent().getType() != Type.BLOCK_CODE) {
			text = text.replace('\n', ' ');
		}

		// Retrieve the image now so we know whether we're going to have something to display later
		// If we don't, then show the alt text instead (if available).
		Drawable imageDrawable = null;
		if (type == Type.IMAGE && imageGetter != null && !TextUtils.isEmpty(element.getAttribute("link"))) {
			imageDrawable = imageGetter.getDrawable(element.getAttribute("link"));
		}

		switch (type) {
			case LIST:
				if (element.getParent() != null
					&& element.getParent().getType() == Type.LIST_ITEM) {
					builder.append("\n");
				}
				break;
			case LINEBREAK:
				builder.append("\n");
				break;
			case LIST_ITEM:
				builder.append(" ");
				if (mOrderedListNumber.containsKey(element.getParent())) {
					int number = mOrderedListNumber.get(element.getParent());
					builder.append(Integer.toString(number) + ".");
					mOrderedListNumber.put(element.getParent(), number + 1);
				}
				else {
					builder.append(mOptions.mUnorderedListItem);
				}
				builder.append("  ");
				break;
			case AUTOLINK:
				builder.append(element.getAttribute("link"));
				break;
			case HRULE:
				// This ultimately gets drawn over by the line span, but
				// we need something here or the span isn't even drawn.
				builder.append("-");
				break;
			case IMAGE:
				// Display alt text (or title text) if there is no image
				if (imageDrawable == null) {
					String show = element.getAttribute("alt");
					if (TextUtils.isEmpty(show)) {
						show = element.getAttribute("title");
					}
					if (!TextUtils.isEmpty(show)) {
						show = "[" + show + "]";
						builder.append(show);
					}
				}
				else {
					// Character to be replaced
					builder.append("\uFFFC");
				}
				break;
		}

		builder.append(text);
		builder.append(concat);
		
		// Don't auto-append whitespace after last item in document. The 'numberOfSiblings'
		// is the number of children the parent of the current element has (including the
		// element itself), hence subtracting a number from that count gives us the index
		// of the last child within the parent.
		if (element.getParent() != null || indexWithinParent < (numberOfSiblings - 1)) {
			if (type == Type.LIST_ITEM) {
				if (element.size() == 0 || !element.children[element.size() - 1].isBlockElement()) {
					builder.append("\n");
				}
			}
			else if (element.isBlockElement() && type != Type.BLOCK_QUOTE) {
				if (type == Type.LIST) {
					// If this is a nested list, don't include newlines
					if (element.getParent() == null || element.getParent().getType() != Type.LIST_ITEM) {
						builder.append("\n");
					}
				}
				else if (element.getParent() != null
					&& element.getParent().getType() == Type.LIST_ITEM) {
					// List items should never double-space their entries
					builder.append("\n");
				}
				else {
					builder.append("\n\n");
				}
			}
		}

		switch (type) {
			case HEADER:
				String levelStr = element.getAttribute("level");
				int level = Integer.parseInt(levelStr);
				setSpan(builder, new RelativeSizeSpan(mOptions.mHeaderSizes[level - 1]));
				setSpan(builder, new StyleSpan(Typeface.BOLD));
				break;
			case LIST:
				setBlockSpan(builder, new LeadingMarginSpan.Standard(mListItemIndent));
				break;
			case EMPHASIS:
				setSpan(builder, new StyleSpan(Typeface.ITALIC));
				break;
			case DOUBLE_EMPHASIS:
				setSpan(builder, new StyleSpan(Typeface.BOLD));
				break;
			case TRIPLE_EMPHASIS:
				setSpan(builder, new StyleSpan(Typeface.BOLD_ITALIC));
				break;
			case BLOCK_CODE:
				setSpan(builder, new LeadingMarginSpan.Standard(mCodeBlockIndent));
				setSpan(builder, new TypefaceSpan("monospace"));
				break;
			case CODE_SPAN:
				setSpan(builder, new TypefaceSpan("monospace"));
				break;
			case LINK:
			case AUTOLINK:
				String link = element.getAttribute("link");
				if (!TextUtils.isEmpty(link) && Patterns.EMAIL_ADDRESS.matcher(link).matches()) {
					link = "mailto:" + link;
				}
				setSpan(builder, new URLSpan(link));
				break;
			case BLOCK_QUOTE:
				// We add two leading margin spans so that when the order is reversed,
				// the QuoteSpan will always be in the same spot.
				setBlockSpan(builder, new LeadingMarginSpan.Standard(mBlockQuoteIndent));
				setBlockSpan(builder, new QuoteSpan(mOptions.mBlockQuoteColor));
				setBlockSpan(builder, new LeadingMarginSpan.Standard(mBlockQuoteIndent));
				setBlockSpan(builder, new StyleSpan(Typeface.ITALIC));
				break;
			case STRIKETHROUGH:
				setSpan(builder, new StrikethroughSpan());
				break;
			case HRULE:
				setSpan(builder, new HorizontalLineSpan(mOptions.mHruleColor, mHruleSize, mHruleTopBottomPadding));
				break;
			case IMAGE:
				if (imageDrawable != null) {
					setSpan(builder, new ImageSpan(imageDrawable));
				}
				break;
		}

		return builder;
	}
private CharSequence recurseElement(Element element, int indexWithinParent, int numberOfSiblings,
			ImageGetter imageGetter) {

		Type type = element.getType();

		boolean isOrderedList = false;
		if (type == Type.LIST) {
			String flagsStr = element.getAttribute("flags");
			if (flagsStr != null) {
				int flags = Integer.parseInt(flagsStr);
				isOrderedList = (flags & Element.F_LIST_ORDERED) != 0;
				if (isOrderedList) {
					mOrderedListNumber.put(element, 1);
				}
			}
		}

		int size = element.size();
		CharSequence[] spans = new CharSequence[size];
		
		for (int i = 0; i < size; i++) {
			spans[i] = recurseElement(element.children[i], i, size, imageGetter);
		}

		// Clean up after we're done
		if (isOrderedList) {
			mOrderedListNumber.remove(this);
		}

		CharSequence concat = TextUtils.concat(spans);

		SpannableStringBuilder builder = new ReverseSpannableStringBuilder();

		String text = element.getText();
		if (element.size() == 0
			&& element.getParent() != null
			&& element.getParent().getType() != Type.BLOCK_CODE) {
			text = text.replace('\n', ' ');
		}

		// Retrieve the image now so we know whether we're going to have something to display later
		// If we don't, then show the alt text instead (if available).
		Drawable imageDrawable = null;
		if (type == Type.IMAGE && imageGetter != null && !TextUtils.isEmpty(element.getAttribute("link"))) {
			imageDrawable = imageGetter.getDrawable(element.getAttribute("link"));
		}

		switch (type) {
			case LIST:
				if (element.getParent() != null
					&& element.getParent().getType() == Type.LIST_ITEM) {
					builder.append("\n");
				}
				break;
			case LINEBREAK:
				builder.append("\n");
				break;
			case LIST_ITEM:
				builder.append(" ");
				if (mOrderedListNumber.containsKey(element.getParent())) {
					int number = mOrderedListNumber.get(element.getParent());
					builder.append(Integer.toString(number) + ".");
					mOrderedListNumber.put(element.getParent(), number + 1);
				}
				else {
					builder.append(mOptions.mUnorderedListItem);
				}
				builder.append("  ");
				break;
			case AUTOLINK:
				builder.append(element.getAttribute("link"));
				break;
			case HRULE:
				// This ultimately gets drawn over by the line span, but
				// we need something here or the span isn't even drawn.
				builder.append("-");
				break;
			case IMAGE:
				// Display alt text (or title text) if there is no image
				if (imageDrawable == null) {
					String show = element.getAttribute("alt");
					if (TextUtils.isEmpty(show)) {
						show = element.getAttribute("title");
					}
					if (!TextUtils.isEmpty(show)) {
						show = "[" + show + "]";
						builder.append(show);
					}
				}
				else {
					// Character to be replaced
					builder.append("\uFFFC");
				}
				break;
		}

		builder.append(text);
		builder.append(concat);
		
		// Don't auto-append whitespace after last item in document. The 'numberOfSiblings'
		// is the number of children the parent of the current element has (including the
		// element itself), hence subtracting a number from that count gives us the index
		// of the last child within the parent.
		if (element.getParent() != null || indexWithinParent < (numberOfSiblings - 1)) {
			if (type == Type.LIST_ITEM) {
				if (element.size() == 0 || !element.children[element.size() - 1].isBlockElement()) {
					builder.append("\n");
				}
			}
			else if (element.isBlockElement() && type != Type.BLOCK_QUOTE) {
				if (type == Type.LIST) {
					// If this is a nested list, don't include newlines
					if (element.getParent() == null || element.getParent().getType() != Type.LIST_ITEM) {
						builder.append("\n");
					}
				}
				else if (element.getParent() != null
					&& element.getParent().getType() == Type.LIST_ITEM) {
					// List items should never double-space their entries
					builder.append("\n");
				}
				else {
					builder.append("\n\n");
				}
			}
		}

		switch (type) {
			case HEADER:
				String levelStr = element.getAttribute("level");
				int level = Integer.parseInt(levelStr);
				setSpan(builder, new RelativeSizeSpan(mOptions.mHeaderSizes[level - 1]));
				setSpan(builder, new StyleSpan(Typeface.BOLD));
				break;
			case LIST:
				setBlockSpan(builder, new LeadingMarginSpan.Standard(mListItemIndent));
				break;
			case EMPHASIS:
				setSpan(builder, new StyleSpan(Typeface.ITALIC));
				break;
			case DOUBLE_EMPHASIS:
				setSpan(builder, new StyleSpan(Typeface.BOLD));
				break;
			case TRIPLE_EMPHASIS:
				setSpan(builder, new StyleSpan(Typeface.BOLD_ITALIC));
				break;
			case BLOCK_CODE:
				setSpan(builder, new LeadingMarginSpan.Standard(mCodeBlockIndent));
				setSpan(builder, new TypefaceSpan("monospace"));
				break;
			case CODE_SPAN:
				setSpan(builder, new TypefaceSpan("monospace"));
				break;
			case LINK:
			case AUTOLINK:
				String link = element.getAttribute("link");
				if (!TextUtils.isEmpty(link) && Patterns.EMAIL_ADDRESS.matcher(link).matches()) {
					link = "mailto:" + link;
				}
				setSpan(builder, new URLSpan(link));
				break;
			case BLOCK_QUOTE:
				// We add two leading margin spans so that when the order is reversed,
				// the QuoteSpan will always be in the same spot.
				setBlockSpan(builder, new LeadingMarginSpan.Standard(mBlockQuoteIndent));
				setBlockSpan(builder, new QuoteSpan(mOptions.mBlockQuoteColor));
				setBlockSpan(builder, new LeadingMarginSpan.Standard(mBlockQuoteIndent));
				setBlockSpan(builder, new StyleSpan(Typeface.ITALIC));
				break;
			case STRIKETHROUGH:
				setSpan(builder, new StrikethroughSpan());
				break;
			case HRULE:
				setSpan(builder, new HorizontalLineSpan(mOptions.mHruleColor, mHruleSize, mHruleTopBottomPadding));
				break;
			case IMAGE:
				if (imageDrawable != null) {
					setSpan(builder, new ImageSpan(imageDrawable));
				}
				break;
		}

		return builder;
	}
you have?".