Ziem My personal blog

How to start a Fragment for a result?

Getting a result from a Fragment is almost identical to the startActivityForResult, setResult, and onActivityResult combo.

In the 1.3.0-alpha04 version of the AndroidX Fragment library, Google introduced new APIs that allow passing data between Fragments.

Added support for passing results between two Fragments via new APIs on FragmentManager. This works for hierarchy fragments (parent/child), DialogFragments, and fragments in Navigation and ensures that results are only sent to your Fragment while it is at least STARTED. (b/149787344)

Thanks to the Fragment Result API, FragmentManager gained two new methods:

How to use it?

In FragmentA, set up FragmentResultListener in the onCreate method:

setFragmentResultListener("request_key") { requestKey: String, bundle: Bundle ->
    val result = bundle.getString("your_data_key")
    // do something with the result
}

In FragmentB, add this code to return the result:

val result = Bundle().apply {
    putString("your_data_key", "Hello!")
}
setFragmentResult("request_key", result)

Start FragmentB e.g. by using:

findNavController().navigate(NavGraphDirections.yourActionToFragmentB())

To close / finish FragmentB call:

findNavController().navigateUp()

Now, your FragmentResultListener will be notified, and you will receive your result.

You can use other methods to achieve something similar:

* I’m using fragment-ktx to simplify the code above.


JJRC H67 - flashing ACRO (Silverware by NotFastEnuf)

Recently I successfully flashed ACRO firmware into my JJRC H67. It wasn’t easy, but I will show you how you can do it.

To do the whole procedure, you will need:

  • ST-LINK V2,
  • ST-LINK Utility app,
  • and some cables.

Then you go through the steps listed on the RCGroups forum, but instead of BoldClash-BWHOOP-B-03 precompiled firmware, you will use this binary. It is a compiled Silverware by NotFastEnuf with the following config:

#define BWHOOP
#define RX_BAYANG_PROTOCOL_TELEMETRY_AUTOBIND
#define USE_MULTI
// #define ARMING CHAN_5

If you are a Mac user, you are going to do some steps differently. You will need Silverware Tools for macOS since ST-LINK Utility is Windows-only software.

  • in step “Erasing the factory firmware” instead of ST-LINK Utility user Unlocker to unlock the chip on your flight controller,
  • in step “Flashing a new firmware” use the Flasher app. You just drag and drop your firmware file (e.g.: h67.hex) into the app’s window.

After this whole procedure, you will be able to bind to your Taranis as I described here.

I also gathered some additional materials you may find useful:

Happy flying!


How to bind the JJRC H36 and H67 to the Taranis Q X7 with the Multiprotocol TX module?

Configuring Taranis Q X7 with the Multiprotocol TX module is pretty straightforward:

  • go to the MODELSEL setting,
  • select an empty row and click Create model,
  • click PAGE and assign a Model name,
  • scroll to the bottom until you find Internal RF setting,
  • set Mode to OFF,
  • go to the External RF and set Mode to PPM,
  • Ch. Range set to CH1-12,
  • go to the MIXER screen by clicking the PAGE button,
  • set CH1 to 100 Ail,
  • set CH2 to 100 Ele,
  • set CH3 to 100 Thr,
  • set CH4 to 100 Rud,
  • now you are ready to go :).

Turn off your Taranis and power on your JJRC drone. Now, hold your sticks in the following positions:

H36

  • left stick – bottom-right position
  • right stick – bottom-right position

H67

  • left stick – bottom position
  • right stick – top-right position

and power on your radio. When JJRC binds, it stops blinking.

Happy flying!


Html class - unsupported tags

As we know, some HTML tags are not supported by the Html class. What can we do about it? Android SDK provides a TagHandler interface that allows us to handle unsupported tags.

Now let’s add <strike /> tag to our lorem string from the previous post.

<string name="lorem"><![CDATA[<b>Lorem ipsum dolor</b> sit <u>amet</u>, consectetur <font color="green">adipiscing</font> elit. <i>Cras ut magna eget erat fermentum dignissim.</i> Aenean interdum ultrices sapien<sup>1</sup>. <font color="red">Vestibulum feugiat ultrices neque, vel pretium massa. Etiam tempor luctus dui eget aliquam.</font> <strike>In nec metus sit amet orci facilisis pretium.</strike>]]></string>

When we use the fromHtml method with one parameter and run the code, we can see that it doesn’t work as intended.

broken strike tag

Because <strike /> is not supported, we have to create TagHandler implementation. As ImageGetter, this interface also has only one method which notifies us when an unsupported tag is found:

public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader);

It is the implementation of the TagHandler interface with <strike /> support:

class StrikeTagHandler implements Html.TagHandler {
    @Override
    public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
        if (tag.equalsIgnoreCase("strike")) {
            processStrike(opening, output);
        }
    }

    private void processStrike(boolean opening, Editable output) {
        int length = output.length();

        if (opening) {
            startStrike(output, length);
        } else {
            endStrike(output, length);
        }
    }

    private void startStrike(Editable output, int length) {
        output.setSpan(new StrikethroughSpan(), length, length, Spannable.SPAN_MARK_MARK);
    }

    private void endStrike(Editable output, int length) {
        Object obj = getLast(output, StrikethroughSpan.class);
        int where = output.getSpanStart(obj);

        output.removeSpan(obj);

        if (where != length) {
            output.setSpan(new StrikethroughSpan(), where, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    }

    private Object getLast(Editable text, Class kind) {
        Object[] objs = text.getSpans(0, text.length(), kind);

        if (objs.length == 0) {
            return null;
        } else {
            for (int i = objs.length; i > 0; i--) {
                if (text.getSpanFlags(objs[i - 1]) == Spannable.SPAN_MARK_MARK) {
                    return objs[i - 1];
                }
            }

            return null;
        }
    }
}

This code is from Android: How to use the Html.TagHandler? StackOverflow question.

When an unsupported tag is detected, the handleTag method is triggered. We use this signal to start and finish processing this tag. When the opening parameter is true, we mark a start of a struck-out text by using the setSpan method with Spannable.SPAN_MARK_MARK. Next, when the end tag is detected (opening is false), we search for the last StrikethroughSpan with Spannable.SPAN_MARK_MARK flag to find start position. Then we use length as our end position. Finally, we apply StrikethroughSpan by calling:

output.setSpan(new StrikethroughSpan(), where, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

It is how we use our StrikeTagHandler:

TextView textView = (TextView) findViewById(R.id.lorem);
String string = getString(R.string.lorem);
Spanned spanned = Html.fromHtml(string, null, new StrikeTagHandler());
textView.setText(spanned);

Below we can see the result: working strike tag


Html class - images

The Html class supports images just like HTML. Let’s see how Html.fromHtml() method handles them. In this blog post, I will show you how to use ImageGetter to display images in the TextView.

First, we need to add <img src="..." /> tag to our HTML string. Next, we see what happens, but we encounter the following problem:

broken img tag

Why was such a square displayed? It’s fromHtml() default behavior, it uses com.android.internal.R.drawable.unknown_image drawable when we don’t pass an ImageGetter object to this method. What is the ImageGetter? It’s an interface with one method getDrawable(String source) which is used by the Html class to retrieve Drawable. We implement this interface when we want to support <img /> tags. source argument is equal to src attribute value. ImageGetter’s getDrawable(String source) is triggered by the Html class everytime it encounters <img /> tag.

Now I will show you an example of how to use the ImageGetter interface and load drawable based on src attribute value.

public class ResourcesImageGetter implements Html.ImageGetter {
    private Context context;

    public ResourcesImageGetter(Context context) {
        this.context = context;
    }

    @Override
    public Drawable getDrawable(String source) {
        String drawableName = source.substring(0, source.lastIndexOf('.'));
        Drawable drawable = getDrawableByName(drawableName);
        if (drawable != null) {
            int width = drawable.getIntrinsicWidth();
            int height = drawable.getIntrinsicHeight();

            drawable.setBounds(0, 0, width, height);
        }

        return drawable;
    }

    private Drawable getDrawableByName(String name) {
        Resources resources = context.getResources();
        String packageName = context.getPackageName();

        final int resourceId = resources.getIdentifier(name, "drawable", packageName);

        return resources.getDrawable(resourceId);
    }
}

The code is rather obvious. Based on the image name, I’m loading the application Drawable resources (e.g. ic_launcher.png will be replaced by drawable/ic_launcher.png image).

As the documentation says, don’t forget to call setBounds() on the Drawable object:

Make sure you call setBounds() on your Drawable if it doesn’t already have its bounds set.

Below we can see the final result: working img tag