Slide 1

Slide 1 text

Android Text The performance and features Seigo Nonaka Android Text @ Google @ttuusskk

Slide 2

Slide 2 text

Text Performance Best practice for text on Android Google I/O 2018 by Clara, Florina, Siyamed.

Slide 3

Slide 3 text

Wait… Is Text Slow?

Slide 4

Slide 4 text

Wait… Is Text Slow? It’s just a text. No, Kidding. If text causes jank, everything is janky. Yes, but only for the long text.

Slide 5

Slide 5 text

Well… it depends.

Slide 6

Slide 6 text

Well… it depends. Text may be a heavy component.

Slide 7

Slide 7 text

Today’s Goal You can write faster apps if you 1. know the what TextView is doing 2. know the tools 3. know the best practice

Slide 8

Slide 8 text

Identify the bottleneck

Slide 9

Slide 9 text

Sample App RecyceclerView with ● Holds TextViews ● Random strings and styles

Slide 10

Slide 10 text

Sample App recyclerView.adapter = object: RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { return Holder( TextView(this@Activity) ) } override fun onBindViewHolder(holder: Holder, position: Int) { holder.view.text = sampleText[position] } }

Slide 11

Slide 11 text

UI Performance Basics Android Performance: UI Google I/O 2017 by Chet, Chris

Slide 12

Slide 12 text

Takeaways from UI performance talk ● Finish within 1 frame = 16 ms on UI thread ● Analyze performance with systrace

Slide 13

Slide 13 text

Let’s see our app!

Slide 14

Slide 14 text

systrace $ systrace.py -a

Slide 15

Slide 15 text

systrace

Slide 16

Slide 16 text

Systrace TextView.onMeasure()

Slide 17

Slide 17 text

Is TextView slower than other Views?

Slide 18

Slide 18 text

Another Sample App RecyceclerView with ● Little more complex layout

Slide 19

Slide 19 text

Microbenchmark

Slide 20

Slide 20 text

Root.onMeasure 20,028 μsec

Slide 21

Slide 21 text

TextView.onMeasure 19,508 μsec (97.4%) 2.6% ImageView + RelativeLayout + LinearLayout Root.onMeasure 20,028 μsec

Slide 22

Slide 22 text

What is View.onMeasure()?

Slide 23

Slide 23 text

View.onMeasure “Measure the view and its content to determine the measured width and the measured height. “ https://developer.android.com/reference/android/view/View.html#onMeasure(int,%20int)

Slide 24

Slide 24 text

ImageView.onMeasure

Slide 25

Slide 25 text

ImageView.onMeasure onMeasure(width={AT_MOST, 640}, height={AT_MOST, 480})

Slide 26

Slide 26 text

onMeasure(width={AT_MOST, 640}, height={AT_MOST, 480}) ImageView.onMeasure 120px 160px

Slide 27

Slide 27 text

ImageView.onMeasure 10px 10px 10px 10px onMeasure(width={AT_MOST, 640}, height={AT_MOST, 480})

Slide 28

Slide 28 text

ImageView.onMeasure setMeasuredDimension(140, 180) 140px 180px onMeasure(width={AT_MOST, 640}, height={AT_MOST, 480})

Slide 29

Slide 29 text

TextView.onMeasure()

Slide 30

Slide 30 text

TextView.onMeasure onMeasure(width={AT_MOST, 640}, height={AT_MOST, 480})

Slide 31

Slide 31 text

TextView.onMeasure val text = "Hello, World!" onMeasure(width={AT_MOST, 640}, height={AT_MOST, 480})

Slide 32

Slide 32 text

TextView.onMeasure val paint = textView.paint (drawing configuration) val text = "Hello, World!" onMeasure(width={AT_MOST, 640}, height={AT_MOST, 480})

Slide 33

Slide 33 text

TextView.onMeasure val paint = textView.paint (drawing configuration) val text = "Hello, World!" Blackbox onMeasure(width={AT_MOST, 640}, height={AT_MOST, 480})

Slide 34

Slide 34 text

TextView.onMeasure Hello, World Blackbox 240px 24px setMeasuredDimension(240, 24) val paint = textView.paint val text = "Hello, World!" onMeasure(width={AT_MOST, 640}, height={AT_MOST, 480})

Slide 35

Slide 35 text

TextView.onMeasure Blackbox onMeasure(width={AT_MOST, 640}, height={AT_MOST, 480})

Slide 36

Slide 36 text

Open the black box

Slide 37

Slide 37 text

Systrace again BoringLayout.isBoring() StaticLayout.Builder.build() TextView.onMeasure() BoringLayout.isBoring() StaticLayout.Builder.build()

Slide 38

Slide 38 text

Layout Build the StaticLayout after options have been set. https://developer.android.com/reference/android/text/StaticLayout.Builder.html https://developer.android.com/reference/android/text/BoringLayout.html StaticLayout.Builder.build() Returns null if not boring; the width, ascent, and descent if boring. BoringLayout.isBoring()

Slide 39

Slide 39 text

Layout Perform line breaking to put longer text in a box. StaticLayout.Builder.build() Check if the text fits in a single line. BoringLayout.isBoring()

Slide 40

Slide 40 text

Layout Perform line breaking to put longer text in a box. StaticLayout.Builder.build() Check if the text fits in a single line. BoringLayout.isBoring() Hmm…. still not clear. We need to go deeper.

Slide 41

Slide 41 text

Text rendering stack TextView Minikin Layout ICU (Unicode Library) HarfBuzz (Text Shaping Library) FreeType (Text Drawing Library) Skia (Graphics Library) Paint Canvas Java Native from Google I/O 2018 Best practices for text on Android (Google I/O '18) Trace point

Slide 42

Slide 42 text

Systrace again and again TextView.onMeasure() BoringLayout.isBoring() StaticLayout.Builder.build() doLayout in Minikin The primitive method of computing the layout of the given text.

Slide 43

Slide 43 text

Systrace again and again Why so many calls? TextView.onMeasure() BoringLayout.isBoring() StaticLayout.Builder.build() doLayout in Minikin The primitive method of computing the layout of the given text.

Slide 44

Slide 44 text

Text Layout

Slide 45

Slide 45 text

Understanding Text Layout This is an example text. INPUT : Serif Corsiva OUTPUT: This is an example text. 240px

Slide 46

Slide 46 text

This is an example text. ␣ ␣ ␣ ␣ Returns null if not boring; the width, ascent, and descent if boring. BoringLayout.isBoring()

Slide 47

Slide 47 text

This is an example text. ␣ ␣ ␣ ␣ doLayout("This is an ", "serif"); This is an 120px Returns null if not boring; the width, ascent, and descent if boring. BoringLayout.isBoring()

Slide 48

Slide 48 text

This is an example text. ␣ ␣ ␣ ␣ This is an 120px example text. 120px Returns null if not boring; the width, ascent, and descent if boring. BoringLayout.isBoring() doLayout("This is an ", "serif"); doLayout("example text", "Corsiva");

Slide 49

Slide 49 text

This is an example text. This is an examp No problem. Go with BoringLayout! Text is too long. Need word wrapping!!! Returns null if not boring; the width, ascent, and descent if boring. BoringLayout.isBoring()

Slide 50

Slide 50 text

Word Wrapping (Line Breaking) (Not the exact the same line breaking algorithm in Android)

Slide 51

Slide 51 text

StaticLayout.Builder.build() This is an text. ␣ ␣ ␣ ␣ example

Slide 52

Slide 52 text

This doLayout("This ", "serif"); This is an text. ␣ ␣ ␣ ␣ StaticLayout.Builder.build() example

Slide 53

Slide 53 text

This is doLayout("is ", "serif"); This is an text. ␣ ␣ ␣ ␣ StaticLayout.Builder.build() example

Slide 54

Slide 54 text

This is an doLayout("an ", "serif"); This is an text. ␣ ␣ ␣ ␣ StaticLayout.Builder.build() example

Slide 55

Slide 55 text

This is an example doLayout("example ", "Corsiva"); This is an text. ␣ ␣ ␣ ␣ StaticLayout.Builder.build() example

Slide 56

Slide 56 text

This is an ex- example ex- ample exam- ple doLayout("ex-", "Corsiva"); This is an text. ␣ ␣ ␣ ␣ StaticLayout.Builder.build() example

Slide 57

Slide 57 text

This is an exam- This is an text. ␣ ␣ ␣ ␣ doLayout("exam-", "Corsiva"); StaticLayout.Builder.build() example ex- ample exam- ple example

Slide 58

Slide 58 text

This is an ex- ample This is an text. ␣ ␣ ␣ ␣ doLayout("ample", "Corsiva"); StaticLayout.Builder.build() example ex- ample exam- ple example

Slide 59

Slide 59 text

This is an ex- text. ample This is an text. ␣ ␣ ␣ ␣ doLayout("text.", "Corsiva"); StaticLayout.Builder.build() example

Slide 60

Slide 60 text

example␣ This is an ex- text. ample This is an text. ␣ ␣ ␣ ␣ StaticLayout.Builder.build() This is an ex- text. ample example exam- This␣ is␣ an␣ text. example␣ For words: 5 times For Hyphenation: 3 times example

Slide 61

Slide 61 text

This is an ex- text. ample This is an text. ␣ ␣ ␣ ␣ StaticLayout.Builder.build() This is an ex- text. ample example exam- This␣ is␣ an␣ example␣ text. example␣ For words: 5 times For Hyphenation: 3 times What happens if we disable hyphenation? example

Slide 62

Slide 62 text

Turn OFF Hyphenation <item name="android:hyphenationFrequency">none</item> textView.apply { hyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE }

Slide 63

Slide 63 text

TextView.onMeasure() BoringLayout.isBoring() StaticLayout.Builder.build()

Slide 64

Slide 64 text

TextView.onMeasure() BoringLayout.isBoring() StaticLayout.Builder.build() TextView.onMeasure() BoringLayout.isBoring() Turn OFF hyphenation

Slide 65

Slide 65 text

TextView.onMeasure() BoringLayout.isBoring() StaticLayout.Builder.build() TextView.onMeasure() BoringLayout.isBoring() Turn OFF hyphenation Why doLayout calls have gone in line break?

Slide 66

Slide 66 text

Layout Cache

Slide 67

Slide 67 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣

Slide 68

Slide 68 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Same Layout Same Layout

Slide 69

Slide 69 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Let’s reuse the previous result!

Slide 70

Slide 70 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Layout Cache Text Shaper .ttf .otf

Slide 71

Slide 71 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf Layout Cache

Slide 72

Slide 72 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf Layout Cache to

Slide 73

Slide 73 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf Layout Cache to to

Slide 74

Slide 74 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf Layout Cache to to

Slide 75

Slide 75 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf Layout Cache be, to to

Slide 76

Slide 76 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf Layout Cache be, to to be,

Slide 77

Slide 77 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf Layout Cache or be, to to be, or

Slide 78

Slide 78 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf Layout Cache not or be, to to be, not or

Slide 79

Slide 79 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf to be, not or Layout Cache not or be to

Slide 80

Slide 80 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf to be, not or to Layout Cache to not or be,

Slide 81

Slide 81 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf to be, not or Layout Cache to not or be, to

Slide 82

Slide 82 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf to be, not or to be, Layout Cache be, to not or

Slide 83

Slide 83 text

Layout Cache to␣ be, or not to be, ␣ ␣ ␣ ␣ Text Shaper .ttf .otf to be, not or to be, Layout Cache be, to not or

Slide 84

Slide 84 text

How this removes doLayout() call from line breaking?

Slide 85

Slide 85 text

Layout Cache (just after BoringLayout.isBoring) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example This is an example text.

Slide 86

Slide 86 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache text. example an is This

Slide 87

Slide 87 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache text. example an is This

Slide 88

Slide 88 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache text. example an is This This

Slide 89

Slide 89 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache text. example an is This This

Slide 90

Slide 90 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache text. example an is This This is

Slide 91

Slide 91 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache text. example an is This This is

Slide 92

Slide 92 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache text. example an is This This is an

Slide 93

Slide 93 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an text. example an is This

Slide 94

Slide 94 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an example text. example an is This

Slide 95

Slide 95 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an text. example an is This ex-

Slide 96

Slide 96 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an text. example an is This ex- ex-

Slide 97

Slide 97 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an text. example an is This ex- exam-

Slide 98

Slide 98 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an exam- text. example an is This ex- exam-

Slide 99

Slide 99 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an ex- text. example an is This ex- exam-

Slide 100

Slide 100 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an ex- text. example an is This ex- exam- ample

Slide 101

Slide 101 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an ex- text. example an is This ex- exam- ample ample

Slide 102

Slide 102 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an ex- text. example an is This ex- exam- ample ample

Slide 103

Slide 103 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an ex- text. example an is This ex- exam- ample ample text.

Slide 104

Slide 104 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an ex- text. example an is This ex- exam- ample ample text.

Slide 105

Slide 105 text

Layout Cache (Line breaking) Text Shaper .ttf .otf Layout Cache text. example an is This This is an text. ␣ ␣ ␣ ␣ example Layout Cache This is an ex- text. example an is This ex- exam- ample ample text.

Slide 106

Slide 106 text

Disable Hyphenation ALL for hyphenation!!! TextView.onMeasure() BoringLayout.isBoring() StaticLayout.Builder.build()

Slide 107

Slide 107 text

Disable hyphenation unless it is really really important to you.

Slide 108

Slide 108 text

Okay, I disabled hyphenation… Is that enough?

Slide 109

Slide 109 text

TextView.onMeasure() BoringLayout.isBoring() Turn OFF Hyphenation 19ms is still slow.... But, all these layout are necessary

Slide 110

Slide 110 text

Any idea of improvement…?

Slide 111

Slide 111 text

Hmm...

Slide 112

Slide 112 text

If we need to pay that cost, Can I do it beforehand?

Slide 113

Slide 113 text

Idea: Use Background Thread

Slide 114

Slide 114 text

Idea: Use Background Thread

Slide 115

Slide 115 text

Idea: Use Background Thread

Slide 116

Slide 116 text

Idea: Use Background Thread

Slide 117

Slide 117 text

What can we do beforehand?

Slide 118

Slide 118 text

Idea 1 Can I compute TextView.onMeasure() beforehand?

Slide 119

Slide 119 text

Idea 1 Can I compute TextView.onMeasure() beforehand? Yes, but it’s hard in general. You have to know the measure specs: width, constraints.

Slide 120

Slide 120 text

Idea 2 Can I warm up the layout cache beforehand?

Slide 121

Slide 121 text

Idea 2 Can I warm up the layout cache beforehand? Yes, you can! This is actually threaded text layout!

Slide 122

Slide 122 text

Threaded text layout with PrecomputedText(Compat)

Slide 123

Slide 123 text

Framework vs AndroidX impl PrecomputedText - the framework impl ● API 28+ ● Keeps copy of layout result. PrecomputedTextCompat - the backported version in AndroidX ● Effective on API 21+ ● Just warms up the layout cache before API 28. ● The cache may be purged when needed. (by default, LRU 5000 words limit)

Slide 124

Slide 124 text

Use PrecomputedTextCompat On API 28+, use framework implementation. Don’t use framework impl and always use AndroidX impl. (Crash happens on some environment.) Between API 21 to 28, warm up layout cache. val computedText = PrecomputedTextCompat.create(text, tv.textMetricsParamsCompat)

Slide 125

Slide 125 text

Utilities for threaded text layout val textFuture = PrecomputedTextCompat.getTextFuture(text, tv.textMetricsParamsCompat, null /* You can pass custom Executor */) // AppcompatTextView will call Future.get() to resolve the measurement when needed. tv.setTextFuture(textFuture)

Slide 126

Slide 126 text

Integrate with RecyclerView

Slide 127

Slide 127 text

RecyclerView prefetch UI Render

Slide 128

Slide 128 text

RecyclerView prefetch UI Render

Slide 129

Slide 129 text

RecyclerView prefetch UI Render

Slide 130

Slide 130 text

RecyclerView prefetch UI Render

Slide 131

Slide 131 text

RecyclerView Prefetch RecyclerView Prefetch by Chet https://medium.com/google-developers/recyclerview-prefetch-c2f269075710

Slide 132

Slide 132 text

Threaded Text Layout with RecyclerView UI Render

Slide 133

Slide 133 text

Threaded Text Layout with RecyclerView UI Render BG

Slide 134

Slide 134 text

Threaded Text Layout with RecyclerView UI Render BG

Slide 135

Slide 135 text

Integrate with RecyclerView recyclerView.adapter = object: RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { return Holder( TextView(this@Activity) ) } override fun onBindViewHolder(holder: Holder, position: Int) { holder.view.text = sampleText[position] } }

Slide 136

Slide 136 text

recyclerView.adapter = object: RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { return Holder( TextView(this@Activity) ) } override fun onBindViewHolder(holder: Holder, position: Int) { holder.view.text = sampleText[position] } } Integrate with RecyclerView

Slide 137

Slide 137 text

recyclerView.adapter = object: RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { return Holder( AppCompatTextView(this@Activity) ) } override fun onBindViewHolder(holder: Holder, position: Int) { Holder.view.apply { setTextFuture(PrecomputedTextCompat.getTextFuture( sampleText[position], textMetricsParamsCompat, null)) } } } Integrate with RecyclerView

Slide 138

Slide 138 text

Systrace result

Slide 139

Slide 139 text

Systrace result PrecomputedText.create() New item comes

Slide 140

Slide 140 text

Integrate with RecyclerView Prefetch Text Layout in RecyclerView by Chris https://medium.com/androiddevelopers/prefetch-text-layout-in-recyclerview-4ac f9103f438

Slide 141

Slide 141 text

Done!

Slide 142

Slide 142 text

Conclusion 0.00 5.00 10.00 15.00 25.00 20.00 22.33 Hyphenation On UI Thread Load milliseconds

Slide 143

Slide 143 text

Conclusion 0.00 5.00 10.00 15.00 25.00 20.00 22.33 7.20 Hyphenation Off Hyphenation On UI Thread Load milliseconds

Slide 144

Slide 144 text

Conclusion 0.00 5.00 10.00 15.00 25.00 20.00 22.33 7.20 1.17 0.62 Hyphenation Off Hyphenation On Hyphenation Off Hyphenation On Precomputed UI Thread Load milliseconds

Slide 145

Slide 145 text

Note ● Always use PrecomputedTextCompat in AndroidX ● There was a giant mutex lock during doing text layout. ○ Removed from API 28 ● Hyphenation depends on the language. ○ No hyphenation for Japanese, i.e. no performance gain by turning off

Slide 146

Slide 146 text

New and old features

Slide 147

Slide 147 text

What’s new in fonts?

Slide 148

Slide 148 text

Downloadable Fonts What’s New in Android Support Library by Clara Bayarri

Slide 149

Slide 149 text

Typeface.Builder ● Replacement for createFromAsset, createFromFile. ● Variable Font Support (later) ● Font Collection Support textView1.typeface = Typeface.Builder(assets, "NotoSansCJK-Regular.ttc") .setTtcIndex(0).build() textView2.typeface = Typeface.Builder(assets, "NotoSansCJK-Regular.ttc") .setTtcIndex(1).build() textView3.typeface = Typeface.Builder(assets, "NotoSansCJK-Regular.ttc") .setTtcIndex(2).build() textView4.typeface = Typeface.Builder(assets, "NotoSansCJK-Regular.ttc") .setTtcIndex(3).build()

Slide 150

Slide 150 text

Variable Font ● OpenType Variable Font ● Either string representation or FontVariationAxis class can be used. textView1.typeface = Typeface.Builder(assets, "AdobeVFPrototype.ttf") .setFontVariationSettings("'wght' 200").build() textView2.typeface = Typeface.Builder(assets, "AdobeVFPrototype.ttf") .setFontVariationSettings("'wght' 400").build() textView3.typeface = Typeface.Builder(assets, "AdobeVFPrototype.ttf") .setFontVariationSettings("'wght' 700").build() textView4.typeface = Typeface.Builder(assets, "AdobeVFPrototype.ttf") .setFontVariationSettings("'wght' 900").build()

Slide 151

Slide 151 text

Locale List Fallback ● Font selector is now aware of locale list ● By default, system locale settings is used. textView1.textLocales = LocaleList.forLanguageTags("en-US,ja-JP") textView2.textLocales = LocaleList.forLanguageTags("en-US,zh-CN") textView3.textLocales = LocaleList.forLanguageTags("en-US,zh-TW") textView4.textLocales = LocaleList.forLanguageTags("ja-JP,zh-TW")

Slide 152

Slide 152 text

Serif Fallback ● System font is now aware of serif font. ● Use serif font if fontFamily=”serif” is specified.

Slide 153

Slide 153 text

What’s new in Layout

Slide 154

Slide 154 text

Performance Improvement ● Removed giant mutex lock during doing text layout. 0 25 50 75 100 milliseconds 125 150 175 API 27 API 27 API 27 API 28 1 thread 2 threads 4 thread 8 threads 34.9 49.0 82.1 318.7 22.1 22.5 26.5 82.6

Slide 155

Slide 155 text

PrecomputedText You are already familiar with this feature.

Slide 156

Slide 156 text

Justification ● Justification by whitespaces ● API is available since API 26, but due to bug, please use it API 28+

Slide 157

Slide 157 text

Line Spacing Improvement ● Avoid glyph overlap for the taller glyph languages. ● Enabled by default API 28+ ● You can move back to old impl by specifying fallbackLineSpacing=”false”

Slide 158

Slide 158 text

Thank you for your attention!

Slide 159

Slide 159 text

Q&A