[MUSIC PLAYING]
FLORINA MUNTENESCU:
Hello, everyone.
I’m Florina Muntenescu.
I’m an engineer in the
Developer Relations team.
SIYAMED SINIR: Hi,
I am Siyamed Sinir.
I am engineer in
UI Toolkit team.
SEIGO NONAKA: Hi.
My name’s Seigo Nonaka.
I’m also engineer
in UI Toolkit team.
FLORINA MUNTENESCU:
Last year, we
told you the basics of
best practices with text.
And this year, we want
to build on top of that.
So if you haven’t seen that
talk yet, go check it out.
We’ll wait.
This year, we looked
again at topics
that you have most problems
with, the ones that you feel
are most challenging.
So in this talk, we’re going
to cover a variety of topics.
Some are wider, more
generally applicable,
and some are more
niche advanced topics.
And the solutions,
as you’ll see,
are either new APIs in queue
or some specific guidance.
So let’s get started.
SEIGO NONAKA: OK, let’s get
started from performance.
The performance is a top
topic in the user experience,
and text is one of the most
heavily used components
in UI Toolkit team.
Despite from the usage, the
most of the internal things
are black box and
how to optimize
for many of developers.
We have been keep improving
the TextView performance
and it shows some utility
tips in less Google I/O.
This year, first let me announce
that the hyphenation is now
turned off by default in Android
Q and AppCompat version 1.1.
As we talked last
year, the hyphenation
has a huge impact to the
TextView performance.
Actually, the 70% of the
text work is for hyphenation.
So we turned off
with by default.
If you need hyphenation,
please manually turn
it own in your application.
To enable the
hyphenations, please
set hyphenation frequency
attribute to normal
in style.xml or layout.xml.
Also, you can call fit
hyphenation frequency method
in your code.
OK, next.
We released the precomputed
text in last Google I/O.
This is a tool for doing text
work in background thread.
This does 90% of
text work beforehand,
selecting fonts
or measuring text.
This is a [INAUDIBLE]
object and it should be
created in background thread.
And we back ported
this craft to jet pack
and available from API 21.
Then this year, we
added new utility APIs
for easy integration with
RecyclerView prefetch.
Before looking into the
details, let’s see the overview
of the RecyclerView prefetch.
This figure shows the work
growth of UI thread and render
thread.
UI thread does some work
and pass the rendering work
to render thread.
The eye icon shows
the timing of VSYNC.
You see here shows a good state,
nothing broke the VSYNC event.
But if some work takes
time and couldn’t
finish until the
next VSYNC event,
it end up with [INAUDIBLE].
In this example, the
lid works takes time
and blocks the next VSYNC event.
This typically happens
when the new item
is appeared by scrolling.
The idea of prefetch is
doing this view item process
in much earlier time when
the UI thread is idle.
If everything goes well, the
workload of the UI thread
have distributed, and we
can prevent UI [INAUDIBLE]..
This is just the overview.
So if you need the more details,
please check the articles
on the Android developer
medium publication.
This is how prefetch
works, but this prefetch
had three limitations.
The prefetch still
works on the UI thread.
If prefetch takes longer
time, that prefetch
still blocks the VSYNC event.
This typically
happens when you set
long, long text to TextView.
One obvious reason
for this problem
is moving some work
to background thread.
Actually, you can move some
text work to background thread
by using PrecomputedText.
However, in general, moving
some work to background set
is not a trivial work.
So we introduce new utility APIs
for make this happen easily.
The API is getTextFuture
in PrecomputedTextCompat
and setTextFuture in
AppCompatTextView.
Let’s see how it works.
When you write the application
with the RecyclerView,
you may set text in
onBindViewHolder callback
like this.
Then, if we move that text
work to background set,
the code looks like this.
Let’s see it line by line.
First, let’s call getTextFuture.
The getTextFuture
schedule text work
on the past
execution and returns
the future of the result.
Once you get the future,
you can set it to
the AppCompatTextView
by calling setTextFuture.
Basically, that’s it.
By coding these two APIs,
you can move the text work
to background set.
This is pretty simple, but
please note that you cannot
change the style after
coding getTextFuture,
because getTextFuture
schedules the text work with
the parameters when it’s called.
So if you change the
style after that,
the async work
result won’t match up
with the parameter
of the TextView.
Then it end up
with the exception.
So if you want to
change the style,
please do it before
calling getTextFuture.
If you need more details
or what is under the hood,
please check the article on
the Android developer medium
publication.
Thank you.
[APPLAUSE]
FLORINA MUNTENESCU:
Apart from performance,
another thing that
everyone needs to work with
is text styling.
But with so many ways of styling
text, which one should you use?
And what’s the precedence
order for each of them?
So one of the easiest
ways to style text
is by just using the
TextView attributes.
But the problem with this
is that this is tedious
and error prone.
If you, for example,
need to update
the color of the
TextViews, you need
to see absolutely every
TextView in your application,
and then do that update
The solution for this
is working with styles.
They bring you consistency,
reusability, and easy updates.
And this actually brings us
to the first precedence order.
So you see here, we have both
the text size in the style
and also in the text attribute.
So which text size will
the text actually have?
Well, the view attributes
overrides the one
from the style.
So what you’ll see here
is a text that’s 16 sp.
Views have a default style.
So for example, for
the button that’s
a subclass of the
TextView, you’ll
see that we’re also using
a theme attribute, that’s
the button style.
Well, in the
Material theme, this
pointed to a certain style
which styles different elements,
including attributes of
the text of the button.
By setting your
default styles, it
means that styling becomes an
opt out rather than opt in.
By default, all buttons,
independent If you’re
adding them to new screens
or you’re refactoring,
will have a default style.
So you’ll only
need to modify them
if you specifically
want to change
the style for the button.
So by default, but
this default style
is going to be overridden by
any style that sits directly
on the view.
The button properties, as some
eagle eye might have seen here,
are set using the
text appearance.
So text appearance actually
functions very similarly
to a style.
Under the hood, the TextView
checks whether the view
has a text appearance.
It loads it.
It applies it to the view.
And then, it adds all
the other attributes,
like the text style, also.
So this means that, as
the precedence order,
the text appearance
is then overridden
by the default style,
and then the style,
and then the view attributes.
But there’s something you should
know about text appearance.
It’s character building.
It only supports
character-level styling.
It doesn’t support
paragraph-level styling,
like line height
or break strategy.
These can be customized here.
In Android Q, we added a new
attribute in text appearance–
the font variation settings.
And the same attribute,
starting from Q,
can be used in TextView
and in AppCompatTextView.
Some of the text
appearance attributes
are also supported in
text appearance span.
Before Q, the text
appearance span
didn’t read some of
the text attributes,
like typeface or shadow.
So starting from Q, the
text appearance span
is updated to read and apply
these attributes, as well.
Also new in Q,
speaking of spans,
we’ve added implementations
to two new spans–
line height span and
line background span.
When applying the span
on top of text styling,
keep in mind that the
properties of the span
set the properties that
are set by the span
will override any other
properties that you
might be setting–
VI style, or default
style, or view.
But what if you want to change
some attributes of the TextView
at the app level?
So let’s say that you want
to change the entire font
in your application.
Well, for this, you
would use themes.
So for example here, we’re
setting the font family
attribute to set the theme.
The theme is part of
the view styling system,
and it overrides anything
that’s supplied in the text
appearance, but it will override
any more specific attributes.
So for the text styling, we
looked at the precedence order
to help you better understand
why or why not style is
applied.
SIYAMED SINIR: Thanks.
Hi again.
[APPLAUSE]
Thank you.
So we have covered tips
related to text styling
and also performance.
And we will continue
with fonts, which
is an important
part of text styling
and also your application’s
brand identity.
Over the years, you
have mentioned to us
about the shortcomings of
font support on Android.
And in the last
few years, we have
added features such as
downloadable fonts and fonts
in XML.
This year, we have improved the
typeface and font-related APIs
based on the further
feedback we got.
Let’s go over a
real-life use case,
and let’s assume
that we have an app.
And in one of our
buttons, we want
to use an icon in
between the text.
And we want this icon to be
rendered using the icon font.
And for the remaining
of the text,
we want to use another
custom font, let’s say, Lato.
When we want to do this,
we are kind of in trouble,
because the button will
accept only a single typeface,
and a typeface can be created
using a single font or font
family.
Actually, in the current API,
we can use a typeface span,
give the icon font into it,
and cover the icon character.
And then for the
whole button, we
can choose to use the Lato font.
However, things will get
much more complicated
if we were to try to
support multiple languages
with their own custom fonts.
Using spans here is definitely
not a scalable solution,
because you will have a lot
of languages to support,
and it’s pretty hard
to accurately identify
different languages
for a given string.
And on top of that,
over the years
I have heard continuously,
parsing emoji, for example,
is pretty hard.
And if you have another
custom emoji font,
that would be a pain.
Therefore, in Android Q, we
added custom fallback builder
to the typeface class.
It enables you to create a
typeface using multiple fonts
or font families.
Then we check our
multi-language use case.
Here we create a builder, and
for each of the languages,
we create a font family and add
the related fonts into them.
And this will also show the
icon font use case, as well,
where this time
again, we put the icon
font as a separate font family
into the final typeface.
Then you have multiple
styles for a font family,
you can add them into the
same font family object.
And whenever you set the text,
we have to use bold style
or mark a portion of the
text to be bold using spans.
The system will choose
the correct bold font
from the given configuration.
When creating a typeface
using this builder,
you can add up to
64 font families.
However, what you cannot do is
you cannot put the fonts that
belong conceptually to different
font families into the same
font family object.
The reason is the system
expects the fonts that
are in the same font family
to have the same code
coverage, which
means that they have
to have one-to-one mapping
between the characters
that they support.
And the other thing that
you cannot do is to put two
of the same styled fonts
into the same font family.
For example, here, if I
were to put Lato bold twice
into the same font family,
I would get an exception.
And then you define a
custom fallback builder.
Here is how the system works.
It does a sequential search
over the string, and also
over the fonts
that are provided.
For example, in
here, it will start
with the Japanese
character, and it
will check if Lato font
supports this character.
If not, it will go to the
second one, see Kosugi,
and at that point, it will try
to cover as many characters as
possible using the same font.
And then it will do the
same thing over again.
And if the string
contains language
that is not supported
with the given font,
the system will use
the system fallback use
case, which is the current
case for Android and typeface.
As a control over
system fallback,
the new API has a function
named setSystemFallback,
where you define what
kind of generic family
should be preferred while
choosing a font from the system
fallback.
Since Lato is a sans
serif font, here I
tell the system that
if a character is not
supported by Lato,
the font that I edit,
I want system to prefer
a sans-serif font.
Just like the current
typeface builders,
while creating a font, you can
set the weight, slant, and also
the variable font
settings on a font object.
And finally, in terms
of font matching,
let’s assume that you added
two different weighted forms
into the same font
family, 400 and 700.
And by using text font
weight attribute on TextView,
you requested to render
this text using a 600 font.
In such mismatches,
the system will
use the closest match or style.
For this case, it will
choose to use 700.
Text font weight was
recently added, I think in P,
to TextView.
And it’s also currently being
read by text appearance span.
SEIGO NONAKA:
Thank you, Siyamed.
[APPLAUSE]
As he explained, we expanded
the font experience in Android Q
for Java applications.
On the other hand, there’s
another strong demand
from NDK application
developers about system fonts.
So we decided to add new
APIs for existing system
fonts from native code.
This would be a great tool for
NDK application filtered text
on the screen, like a games,
document viewer, or browsers.
First, what is a system font?
Android supports
over 100 languages,
and each languages may
require different font files.
For example, to draw Hindi,
you may need Devanagari font.
In case of pixels
three, to support
this large number
of languages, it
has over 270 font
files are installed.
To draw text, NDK application,
like document viewer,
needs to know which system
font can render the given text.
This is not a trivial question.
So we added two
new APIs for this.
The API is font matcher API.
This is a interface
of the system
internal font selection engine.
This font selection engine
is also used by the TextView,
so you can get the same
result as in the TextView.
OK, let’s see how this works.
Let’s think with this example.
The core API is
AFontMatcher match function.
This takes a search string
and returns two outputs–
font and length.
Please note that this API
is simplified for explaining
its behaviors.
The real API is written in
C and takes more parameters.
Anyway, this function
would return,
in this example, font
NotoSansCJK-Regular and length
3.
This length 3 means
first three characters
can be rendered
with a return font.
In this case, NotoSansCJK.
OK, now we know the font for
the first three characters.
What about remaining?
Since we know the
first three characters,
let’s advance the search
range, in this case,
moving starting offset by 3.
Then, for the same
function again.
On the second time,
this API returns
font Roboto-Regular
and length 8.
Again, this 8 means the
next eight characters–
in this example, it
includes a white space–
can render the
Roboto-Regular front.
Then, advance search range,
then call function again.
On the third time, now, really,
it is the end of the string.
So we get all fonts for
the given characters.
As you’ve seen it, by keep
coding these functions,
you can get font files
for all characters.
This is how this API works.
But please note that this API
never returns null pointers.
If no font can render
the given font,
this API still returns
a byte font object.
This font of that should be used
for drawing missing with symbol
called Tofu.
Similarly, even if it has
no font exactly matches
with the given
parameters, this function
still returns a font which
should have a closest style.
OK.
This is font matching API.
This API gives an
answer to the question,
what font should be
used for the text?
On the other hand, there’s
another frequently asked
question.
What fonts are
installed in the device?
To answer these
questions, we also
add a new API called
font enumeration API.
This font enumeration
API gives user
access to the
system-installed font files.
Let’s see how to use this.
The Java API is really simple.
You can just call system
fonts, get the available fonts.
This gives you the set of
system-installed font files,
and you can get the clear
path of the system fonts.
In case of NDK, it starts
from creating iterator object.
By keep calling next
function to iterator,
you can access all
system-installed font files.
But please note that
the returning order
doesn’t mean anything here.
For example, even
if font A comes
before font B, that doesn’t
mean font A has higher
priority than font
B. This next function
returns in random order.
Finally, there’s
another note here.
This font enumeration
API is not so fast,
so we recommend you
to cache the result.
Since the system
font configuration
is read only and modified
only by the system update,
so you can keep the
result for a longer time
until the next system update.
Thank you.
[APPLAUSE]
FLORINA MUNTENESCU: One of
the most used subclasses
of TextView is EditText.
And pretty much everything
that applies to the TextView
also applies to EditText.
But on top of this,
there are also
other things that
you need to handle,
things like layout, styling,
keyboard configuration, input
formatting,
internationalization, and more.
Unfortunately, we
don’t have time
to go over all of these today.
But we will cover some of them.
So first of all, when
working with EditText,
you actually interact with
three different processes.
The first one is
your application.
The next one is
the soft keyboards,
named Input Method Service.
And then the third one
is the system process
that orchestrates those two.
And because this is an
inter-process communication,
you might see in some
cases a slight delay
between key events
entered in the UI
and them showing up in the app.
So visually, EditText has
the following components–
the hints, the text, the
background, the selection,
the cursor, and the cursor
and selection handles.
The background, cursor, and
handles, the colors for these
are updated when you
set the color secondary
in your application theme.
They are actually
just drawables that
use colorControlNormal
and colorControlActivated
in their definitions.
So actually, you can also modify
those theme overlay attributes
to change their color.
Each of these
drawables themselves
can also be updated
using related attributes.
But probably the one
you want to set the most
is editTextBackground.
Finally, textColorHint,
editTextColor,
and textHighlightColor
are also used
to update the color
of the other three.
Apart from these attributes,
just like TextView, EditText
has its own default style, which
is the editTextStyle attribute.
And this can be ported
to your own custom style.
So use this attribute to
change any EditText view
attributes, such as text
size, or text style.
[APPLAUSE]
SIYAMED SINIR: As you
all know, EditText
has support for
compound drawables.
And sometimes we see
those compound drawables
are being used as action
buttons on the EditText,
such as a clear action.
However, using
drawables as buttons
comes with a lot of
constraints, and it definitely
negatively impacts the
final user experience.
Things like, when you
add an action button,
you will probably want to
show the ripples on touch,
maybe animate the icons,
have more than one icon
on each side.
And then you will also have
the accessibility requirements.
All of these
features are already
supported by the existing
[INAUDIBLE] layout system.
And therefore, we will
suggest to use them instead.
Apart from being
convenient at first,
I believe that there
might be two reasons why
people would like to
choose to go that way
and use the drawables.
One of them is having the
same EditText look and feel
over the whole group,
and the other one
is being able to
contract and expand
the editable area based on
the visibility of the button.
You should definitely
use text input layout,
and that will cover
a lot of use cases.
However, if you have
application-specific
requirements that are not
supported by text input layout,
you should create your
own view group and layout.
And in order to address the
issue of having the same look
and feel, you can set
the EditText background
to null, and use the exact
same background that is already
in the system for
the view group.
The only thing we have
to do is, in order
to respond to the state
changes for the drawable, such
as pressed and focused,
you have to add
the addStatesFromChildren
attribute to the parent layout.
Another common issue in terms
of EditText that we are aware of
is how the keyboard plays with
a possible input validation
error.
Depending on the location
of the input field,
the error can remain
behind the keyboard,
and you really want
the users to be
able to see what went
wrong, let’s say,
when they were going
through a sign up process.
This is currently the case
also for the text input layout,
and there is an open
ticket about it.
But until we get to address this
issue in the material library,
here is what we can do in order
to make those errors visible.
There is already
a system in place
that keeps the
editable area visible
after the keyboard shows up.
And all we want to do is to
tell the system, instead of
the edit text area, which
is the green box in here,
use the yellow box.
And in order to do that, we
have to extend from EditText
and override three functions.
I have added the sample code
to the URL given in the slide.
But I will go through
the functions briefly.
Get focused rectangle is used
to find the next focusable
widget, updates a rectangle.
Get globally visible rectangle
defines the visible array
of a view.
And finally, request
rectangle on screen
is used by EditText to
request from the system
to make a certain area visible,
in terms of the edit text where
the cursor is.
Get focused rectangle
implementation is pretty
straightforward and simple.
You let the edit text to
fill in the rectangle,
and you just update the
bottom of the final rectangle
to be the parent’s button.
And you do the same thing for
the global visible rectangle.
Finally, for request
rectangle on screen,
again we let the edit text
to request its own rectangle,
and then we request
another rectangle,
which is at the bottom
of our parent layout.
The number 10 here is
just a magic number
to define a rectangle at
the bottom of the parent.
Going back to the EditText
configuration and how
it works with keyboard–
as you all know, when you
set the input type attribute
to text password, the
characters on the screen
will be invisible.
However, this
information is also
being shared to the keyboard in
order to change its behavior.
Now, the keyboard itself
is another application
that can be installed
from Play Store.
Therefore, they can
define their own behavior
based on the signals they get.
Since we cannot rely
on their behavior,
you still have to validate
the input on our side.
However, using the correct
input types and IME options
is important to reduce the
friction for the end user
as much as possible.
And when you set the input
type to number password,
you have a visible
change on the keyboard,
where they show the number pad.
If you have a custom
component, let’s say,
and you toggle the
visibility of the password,
you still want to signal
the keyboard that this
is a password field,
and they should not
learn about what the user
types, because you don’t want
the keyboard itself, which
is not under your control,
to show back the user, here is
your password, I know about it.
Because it gets a little
creepy for the users.
And the cases where you don’t
want the keyboard to learn
is not limited to
the password fields.
Things like an incognito
mode, such as in Chrome,
or a promo code in
your checkout screen
are really things that you
don’t want the keyboard
to learn about.
For those cases, you can add
the no personalized learning
flag to the IME options.
One more IME option that
is important in my opinion
is flag force ASCII.
A lot of times, we have seen
that developers are expecting
when they set the password, when
they set the input type to text
password, they
expect the keyboard
to show an ASCII keyboard.
However, text password is
definitely not a strong signal
for them to switch
to ASCII keyboard.
So if you have an ASCII-only
field, such as username
and password, maybe,
you might want
to add this flag to IME options.
One last case that can
happen for applications
is the control over the
application language,
text field language, and
the keyboard language.
If you have an
application such as
a language-learning application
or a translation application,
there might be a case
where the main language
of the application is
different than the language
of the edit text,
which can be different
than the language
of the keyboard,
because the user can set
any language that they want.
If you want to
signal to keyboard
to use a specific language
and switch to that language,
you can use set IME hint locales
function on the EditText.
Since we mentioned that
keyboard behavior depends
on the keyboard
implementation, and they
can define their
own behavior, there
might be times
where you might want
to learn about which keyboard
is active at any given time.
You can read the active
keyboard from the settings,
and this will give you the
class name and the package
name of the keyboard.
FLORINA MUNTENESCU: We covered
so many fantastic things
with text in this talk.
But let’s see what are
some of the key things we
should remember.
First, in terms of
performance, keep in mind
that the hyphenation is
now turned off by default
in Android Q and AppCompat 1.1.
So if you need it, enable it.
And also, you should
use PrecomputedText
with RecyclerView prefetch.
For text styling, keep in
mind the precedence order.
If you’re trying
to style something
and you don’t see
the results, it’s
likely been overridden
by something
with a higher precedence.
If you need to support
multiple fonts in your app,
use the custom
fallback builder API.
To find the font used by
the system, use the font
matcher API.
And then, to find all
the installed fonts,
use the font enumeration API.
In terms of EditText,
use the theme attributes
and the Android’s edit text
style to style your edit texts.
Make sure you don’t use the
EditText drawables as actions,
so you can enable extensibility
and maintainability.
And also, use IME flags
to configure soft keyboard
for a better user experience.
So these were some top tips
to make your text terrific.
Thank you.
[MUSIC PLAYING]