[Xposed Framework Modules] Roughy:
Exi for Swiftkey 2.6.0 release

2.6.0 [03.03.2020 ] - Compatibility, 10 Emoji, Newline action ( Stable: 7.4.9.11 Beta: 7.5.0.8 )

Changes in 2.6.0

Added

- Auto-width emoji panels

- Insert Newline text action

Fixed

- Compatibility targeting 7.5.0.8 ( Emoji, jumping cursor, prediction bar stuff )

Changed

- Updated to Android 10 ( Unicode 13.0 ) Emoji ( Properly this time )

- Swipe-selection RTL support disabled by default

- Updated French translations

The Xposed Installer app does not appear to be refreshing properly and may not list the latest version.

Please download it directly from the Xposed Repository below using a browser.

Download:

Exi for Swiftkey on Xposed module repository

My own mirror of all versions

Notes:

XDA was having a bit of a breakdown, so here's a belated release post.

Compatibility

The primary reason everything broke was a completely new one.

When Java loads the methods of a class, it also has to load all the classes those methods refer to.

However, if a method happens to refer to a class that java is unable to load ( because it isn't included ), it... fails.

This means we can't search for it ( because our profiler attempts to match the methods, which it cannot load ), and we cannot hook it ( because we can't get the methods ).

The class responsible for generating the toolbar/prediction bar layouts happens to include some classes in the microsoft namespace that, from what I can tell, just are not included, neither in the base apk nor any of its split apks. How Android manages to run it at the end of the day I do not know ( maybe it's just an unused remnant ? ), but hooking anything in that class is no longer an option. Luckily an almost identical entry point was found earlier in the stacktrace, so with a few tweaks all is good.

The same can not be said for the changes they've made to the toolbar. The button for expanding and collapsing it used to be a simple thing we could move anywhere we wanted in the layout, but now they'll constantly spawn new instances and reset the visibility of the thing, making it a bit of a pain to deal with. As a result we now have to keep track of all instances of the button, change the visibility by messing with its layout parameters, and replace it completely with our own button if we want to do anything but show/hide it. It's all a massive pain, and the codebase grows ever messier.

Preventing-jumping-cursor also broke, simply because the profile searching for the class found the wrong class.

I originally set this up to chain two different profiles, using the first class to help find the second one that we were actually after, but at some point I... apparently messed this up and it wasn't doing this. All is good now though.

Disable RTL swipe-selection by default

While I have worked out most of the issues introduced by adding support for RTL text, it still causes the occasional glitch in certain apps, mostly near the end of the text or by line breaks. RTL support will now be disabled by default, so you'll want to go enable it again in the settings if you rely on it.

Newline text action

There is now a text action to inserts a newline that can be triggered via hotkeys or the quick menu. It just inputs a \n

Emoji panel auto-width

While I was working on another project I came across Flexbox-Layout, which as it name implies allows for layout behavior similar to CSS's own Flexbox. That is to say, if there isn't enough space to display something on the current line, push it to the next line.

It turns out they also have a RecyclerView LayoutManager we can use, which means we can finally have emoji panels that display as many emoji on-screen as possible, rather than being forced to define a set number of columns. The recents panel already does this, but for performance reasons that solution was not really feasible for a larger number of emoticons.

The Reddit and Japanese emoticon panels already default to this new setting ( AUTO, where 0 would be in the column size thing ), as do new panels.

Android 10 emoji

Emoji suck, change my mind.

Last time we tried this I just grabbed the emoji from Swiftkey, who evidently has not bothered updating their emoji since... quite a while back.

Next I turned to Emojipedia, but it turns that while their "new in Unicode 13.0!" lists are accurate, their own lists of emoji are quite out of data.

Apparently the only way to to do this is to get the information straight from the horse's mouth, as the Unicode people do a pretty good job of organizing their stuff.

But hang on, this list has a bunch of duplicates, not to mention all the skin-tone variants are listed separately!

We handle the skin color stuff ourselves, so just filter anything with "skin tone" in the name.

The other duplicates are a bit more interesting.

If you've been with us for a while you might recall that we had a few symbol emoji that would show up as monochrome characters instead of the bitmap emoji.

The reason for this is that many symbols that now have emoji also have unicode symbols at the same codepoint that not only predate the emoji, but are preferred for display purposes. That means that many emoji will not display as emoji unless you explicitly request it by appending the \uFE0F variant selector ( or \uFE0E if you want the monochrome version ).

For instance, these two are the same emoji \u2639, but by itself it will display as a monochrome symbol, and requires the \uFE0F variant selector to display in color:

2639 FE0F ; fully-qualified # ☹️ E0.7 frowning face

2639 ; unqualified # ☹ E0.7 frowning face

Previously I had solved this problem by just adding the appropriate variant selector to everything. This is perfectly fine, but some keyboard ( I'm looking at you, Swiftkey, unless they've fixed it since I last checked ) do not handle this character correctly. The specific sequence of codepoints, ending in the variant selector, should be treated as a single character. The variant selector is a zero-width character meaning you do not see it, but when you move your cursor to an emoji that uses this selector, and then hit backspace, it will first delete the variant selector individually, and the actual emoji remains until you hit backspace again. Not our problem, but annoying none the less.

In the list above "fully-qualified" means that, given that sequence of codepoints, the bitmap version is what will be displayed.

Unqualified is the opposite, meaning the variant selector is required ( or it's the monochrome symbol, as they are also listed.

minimally-qualified I don't really get.

Thankfully the list always includes the fully-qualified equivalents for everything, so we can just strip any unqualified or minimally-qualified entries and we'll get the complete list of emoji without duplicates, and only using the variant selector where it's actually necessary.

This raw data does not tell us which emoji support skin-tone modifiers though, nor whether or not we are able to render them.

Primary renderability is handled by loading all the fonts present on the device and checking if any of them have bitmap entries for those codepoints.

For emoji that consist of multiple codepoints ( e.g. family emoji, or any emoji + skin tone modifier ) we also chuck the string at a function that Android provides that tells us the rendered width of each input character. An emoji that consists of multiple characters should only render as a single character, so if any of the characters other than the very first one are wider than 0 then it is rendering the specified string as multiple symbols, and should thus be considered unrenderable on this device.

For some reason they decided to change the behavior of this in Android 10, and all the secondary characters now have a width of 0 even when they are rendered as separate characters. We work around this by measuring the combined height/width of the rendered output and, if the text is significantly wider than its height, assume that it's rendering it as multiple characters instead of a single one, and the emoji it's supposed to be rendering is not available.

There's also the headache of emoji with mixed skin tones, but I honestly have no idea where to even begin implementing that so I'm... just gonna pretend it's not a thing for now.

Finally, if you are on Pie or later first emoji ( smileys and stuff ) has been separate into smileys and people, as it has grown far too large for a single category. You can revert to the whole combined version by going to settings - emoji version - and selecting "post nougat".

If you are on Oreo 8.0 or earlier you can do the same and set it to "post pie" instead to get the split version.