• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.graphics.text;
18 
19 import static com.android.text.flags.Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN;
20 import static com.android.text.flags.Flags.FLAG_WORD_STYLE_AUTO;
21 
22 import android.annotation.FlaggedApi;
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.SuppressLint;
27 import android.os.Build;
28 import android.os.LocaleList;
29 import android.os.Parcel;
30 import android.os.Parcelable;
31 
32 import dalvik.system.VMRuntime;
33 
34 import java.lang.annotation.Retention;
35 import java.lang.annotation.RetentionPolicy;
36 import java.util.Objects;
37 
38 /**
39  * Specifies the line-break strategies for text wrapping.
40  *
41  * <p>See the
42  * <a href="https://www.w3.org/TR/css-text-3/#line-break-property" class="external">
43  * line-break property</a> for more information.
44  */
45 @android.ravenwood.annotation.RavenwoodKeepWholeClass
46 public final class LineBreakConfig implements Parcelable {
47     /**
48      * No hyphenation preference is specified.
49      *
50      * <p>
51      * This is a special value of hyphenation preference indicating no hyphenation preference is
52      * specified. When overriding a {@link LineBreakConfig} with another {@link LineBreakConfig}
53      * with {@link Builder#merge(LineBreakConfig)} function, the hyphenation preference of
54      * overridden config will be kept if the hyphenation preference of overriding config is
55      * {@link #HYPHENATION_UNSPECIFIED}.
56      *
57      * <p>
58      * <pre>
59      *     val override = LineBreakConfig.Builder()
60      *          .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
61      *          .build();  // UNSPECIFIED if no setHyphenation is called.
62      *     val config = LineBreakConfig.Builder()
63      *          .setHyphenation(LineBreakConfig.HYPHENATION_DISABLED)
64      *          .merge(override)
65      *          .build()
66      *     // Here, config has HYPHENATION_DISABLED for line break config and
67      *     // LINE_BREAK_WORD_STYLE_PHRASE for line break word style.
68      * </pre>
69      *
70      * <p>
71      * This value is resolved to {@link #HYPHENATION_ENABLED} if this value is used for text
72      * layout/rendering.
73      */
74     @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
75     public static final int HYPHENATION_UNSPECIFIED = -1;
76 
77     /**
78      * The hyphenation is disabled.
79      */
80     @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
81     public static final int HYPHENATION_DISABLED = 0;
82 
83     /**
84      * The hyphenation is enabled.
85      *
86      * Note: Even if the hyphenation is enabled with a line break strategy
87      * {@link LineBreaker#BREAK_STRATEGY_SIMPLE}, the hyphenation will not be performed unless a
88      * single word cannot meet width constraints.
89      */
90     @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
91     public static final int HYPHENATION_ENABLED = 1;
92 
93     /** @hide */
94     @IntDef(prefix = { "HYPHENATION_" }, value = {
95             HYPHENATION_UNSPECIFIED, HYPHENATION_ENABLED, HYPHENATION_DISABLED,
96     })
97     @Retention(RetentionPolicy.SOURCE)
98     public @interface Hyphenation {}
99 
100     /**
101      * No line break style is specified.
102      *
103      * <p>
104      * This is a special value of line break style indicating no style value is specified.
105      * When overriding a {@link LineBreakConfig} with another {@link LineBreakConfig} with
106      * {@link Builder#merge(LineBreakConfig)} function, the line break style of overridden config
107      * will be kept if the line break style of overriding config is
108      * {@link #LINE_BREAK_STYLE_UNSPECIFIED}.
109      *
110      * <pre>
111      *     val override = LineBreakConfig.Builder()
112      *          .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
113      *          .build();  // UNSPECIFIED if no setLineBreakStyle is called.
114      *     val config = LineBreakConfig.Builder()
115      *          .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
116      *          .merge(override)
117      *          .build()
118      *     // Here, config has LINE_BREAK_STYLE_STRICT for line break config and
119      *     // LINE_BREAK_WORD_STYLE_PHRASE for line break word style.
120      * </pre>
121      *
122      * <p>
123      * This value is resolved to {@link #LINE_BREAK_STYLE_NONE} if the target SDK version is API
124      * {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or before and this value is used for text
125      * layout/rendering. This value is resolved to {@link #LINE_BREAK_STYLE_AUTO} if the target SDK
126      * version is API {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} or after and this value is
127      * used for text layout/rendering.
128      */
129     @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
130     public static final int LINE_BREAK_STYLE_UNSPECIFIED = -1;
131 
132     /**
133      * No line-break rules are used for line breaking.
134      */
135     public static final int LINE_BREAK_STYLE_NONE = 0;
136 
137     /**
138      * The least restrictive line-break rules are used for line breaking. This
139      * setting is typically used for short lines.
140      */
141     public static final int LINE_BREAK_STYLE_LOOSE = 1;
142 
143     /**
144      * The most common line-break rules are used for line breaking.
145      */
146     public static final int LINE_BREAK_STYLE_NORMAL = 2;
147 
148     /**
149      * The most strict line-break rules are used for line breaking.
150      */
151     public static final int LINE_BREAK_STYLE_STRICT = 3;
152 
153     /**
154      * The line break style that used for preventing automatic line breaking.
155      *
156      * This is useful when you want to preserve some words in the same line by using
157      * {@link android.text.style.LineBreakConfigSpan} or
158      * {@link android.text.style.LineBreakConfigSpan#createNoBreakSpan()} as a shorthand.
159      * Note that even if this style is specified, the grapheme based line break is still performed
160      * for preventing clipping text.
161      *
162      * @see android.text.style.LineBreakConfigSpan
163      * @see android.text.style.LineBreakConfigSpan#createNoBreakSpan()
164      */
165     @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
166     public static final int LINE_BREAK_STYLE_NO_BREAK = 4;
167 
168     /**
169      * A special value for the line breaking style option.
170      *
171      * <p>
172      * The auto option for the line break style set the line break style based on the locale of the
173      * text rendering context. You can specify the context locale by
174      * {@link android.widget.TextView#setTextLocales(LocaleList)} or
175      * {@link android.graphics.Paint#setTextLocales(LocaleList)}.
176      *
177      * <p>
178      * In the API {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, auto option does followings:
179      * - If at least one locale in the locale list contains Japanese script, this option is
180      * equivalent to {@link #LINE_BREAK_STYLE_STRICT}.
181      * - Otherwise, this option is equivalent to {@link #LINE_BREAK_STYLE_NONE}.
182      *
183      * <p>
184      * Note: future versions may have special line breaking style rules for other locales.
185      */
186     @FlaggedApi(FLAG_WORD_STYLE_AUTO)
187     public static final int LINE_BREAK_STYLE_AUTO = 5;
188 
189     /** @hide */
190     @IntDef(prefix = { "LINE_BREAK_STYLE_" }, value = {
191             LINE_BREAK_STYLE_NONE, LINE_BREAK_STYLE_LOOSE, LINE_BREAK_STYLE_NORMAL,
192             LINE_BREAK_STYLE_STRICT, LINE_BREAK_STYLE_UNSPECIFIED, LINE_BREAK_STYLE_NO_BREAK,
193             LINE_BREAK_STYLE_AUTO
194     })
195     @Retention(RetentionPolicy.SOURCE)
196     public @interface LineBreakStyle {}
197 
198     /**
199      * No line break word style is specified.
200      *
201      * This is a special value of line break word style indicating no style value is specified.
202      * When overriding a {@link LineBreakConfig} with another {@link LineBreakConfig} with
203      * {@link Builder#merge(LineBreakConfig)} function, the line break word style of overridden
204      * config will be kept if the line break word style of overriding config is
205      * {@link #LINE_BREAK_WORD_STYLE_UNSPECIFIED}.
206      *
207      * <pre>
208      *     val override = LineBreakConfig.Builder()
209      *          .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
210      *          .build();  // UNSPECIFIED if no setLineBreakWordStyle is called.
211      *     val config = LineBreakConfig.Builder()
212      *          .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
213      *          .merge(override)
214      *          .build()
215      *     // Here, config has LINE_BREAK_STYLE_STRICT for line break config and
216      *     // LINE_BREAK_WORD_STYLE_PHRASE for line break word style.
217      * </pre>
218      *
219      * This value is resolved to {@link #LINE_BREAK_WORD_STYLE_NONE} if the target SDK version is
220      * API {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or before and this value is used for text
221      * layout/rendering. This value is resolved to {@link #LINE_BREAK_WORD_STYLE_AUTO} if the target
222      * SDK version is API {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} or after and this value is
223      * used for text layout/rendering.
224      */
225     @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
226     public static final int LINE_BREAK_WORD_STYLE_UNSPECIFIED = -1;
227 
228     /**
229      * No line-break word style is used for line breaking.
230      */
231     public static final int LINE_BREAK_WORD_STYLE_NONE = 0;
232 
233     /**
234      * Line breaking is based on phrases, which results in text wrapping only on
235      * meaningful words.
236      *
237      * <p>Support for this line-break word style depends on locale. If the
238      * current locale does not support phrase-based text wrapping, this setting
239      * has no effect.
240      */
241     public static final int LINE_BREAK_WORD_STYLE_PHRASE = 1;
242 
243     /**
244      * A special value for the line breaking word style option.
245      *
246      * <p>
247      * The auto option for the line break word style does some heuristics based on locales and line
248      * count.
249      *
250      * <p>
251      * In the API {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, auto option does followings:
252      * - If at least one locale in the locale list contains Korean script, this option is equivalent
253      * to {@link #LINE_BREAK_WORD_STYLE_PHRASE}.
254      * - If not, then if at least one locale in the locale list contains Japanese script, this
255      * option is equivalent to {@link #LINE_BREAK_WORD_STYLE_PHRASE} if the result of its line
256      * count is less than 5 lines.
257      * - Otherwise, this option is equivalent to {@link #LINE_BREAK_WORD_STYLE_NONE}.
258      *
259      * <p>
260      * Note: future versions may have special line breaking word style rules for other locales.
261      */
262     @FlaggedApi(FLAG_WORD_STYLE_AUTO)
263     public static final int LINE_BREAK_WORD_STYLE_AUTO = 2;
264 
265     /** @hide */
266     @IntDef(prefix = { "LINE_BREAK_WORD_STYLE_" }, value = {
267         LINE_BREAK_WORD_STYLE_NONE, LINE_BREAK_WORD_STYLE_PHRASE, LINE_BREAK_WORD_STYLE_UNSPECIFIED,
268             LINE_BREAK_WORD_STYLE_AUTO
269     })
270     @Retention(RetentionPolicy.SOURCE)
271     public @interface LineBreakWordStyle {}
272 
273     /**
274      * A builder for creating a {@code LineBreakConfig} instance.
275      */
276     public static final class Builder {
277         // The line break style for the LineBreakConfig.
278         private @LineBreakStyle int mLineBreakStyle = LineBreakConfig.LINE_BREAK_STYLE_UNSPECIFIED;
279 
280         // The line break word style for the LineBreakConfig.
281         private @LineBreakWordStyle int mLineBreakWordStyle =
282                 LineBreakConfig.LINE_BREAK_WORD_STYLE_UNSPECIFIED;
283 
284         private @Hyphenation int mHyphenation = LineBreakConfig.HYPHENATION_UNSPECIFIED;
285 
286         /**
287          * Builder constructor.
288          */
Builder()289         public Builder() {
290             reset(null);
291         }
292 
293         /**
294          * Merges line break config with other config
295          *
296          * Update the internal configurations with passed {@code config}. If the config values of
297          * passed {@code config} are unspecified, the original config values are kept. For example,
298          * the following code passes {@code config} that has {@link #LINE_BREAK_STYLE_UNSPECIFIED}.
299          * This code generates {@link LineBreakConfig} that has line break config
300          * {@link #LINE_BREAK_STYLE_STRICT}.
301          *
302          * <pre>
303          *     val override = LineBreakConfig.Builder()
304          *          .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
305          *          .build();  // UNSPECIFIED if no setLineBreakStyle is called.
306          *     val config = LineBreakConfig.Builder()
307          *          .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
308          *          .merge(override)
309          *          .build()
310          *     // Here, config has LINE_BREAK_STYLE_STRICT of line break config and
311          *     // LINE_BREAK_WORD_STYLE_PHRASE of line break word style.
312          * </pre>
313          *
314          * @see #LINE_BREAK_STYLE_UNSPECIFIED
315          * @see #LINE_BREAK_WORD_STYLE_UNSPECIFIED
316          *
317          * @param config an override line break config
318          * @return This {@code Builder}.
319          */
320         @SuppressLint("BuilderSetStyle")
321         @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
merge(@onNull LineBreakConfig config)322         public @NonNull Builder merge(@NonNull LineBreakConfig config) {
323             if (config.mLineBreakStyle != LINE_BREAK_STYLE_UNSPECIFIED) {
324                 mLineBreakStyle = config.mLineBreakStyle;
325             }
326             if (config.mLineBreakWordStyle != LINE_BREAK_WORD_STYLE_UNSPECIFIED) {
327                 mLineBreakWordStyle = config.mLineBreakWordStyle;
328             }
329             if (config.mHyphenation != HYPHENATION_UNSPECIFIED) {
330                 mHyphenation = config.mHyphenation;
331             }
332             return this;
333         }
334 
335         /**
336          * Resets this builder to the given config state.
337          *
338          * @param config a config value used for resetting. {@code null} is allowed. If {@code null}
339          *              is passed, all configs are reset to unspecified.
340          * @return This {@code Builder}.
341          * @hide
342          */
reset(@ullable LineBreakConfig config)343         public @NonNull Builder reset(@Nullable LineBreakConfig config) {
344             if (config == null) {
345                 mLineBreakStyle = LINE_BREAK_STYLE_UNSPECIFIED;
346                 mLineBreakWordStyle = LINE_BREAK_WORD_STYLE_UNSPECIFIED;
347                 mHyphenation = HYPHENATION_UNSPECIFIED;
348             } else {
349                 mLineBreakStyle = config.mLineBreakStyle;
350                 mLineBreakWordStyle = config.mLineBreakWordStyle;
351                 mHyphenation = config.mHyphenation;
352             }
353             return this;
354         }
355 
356         // TODO(316208691): Revive following removed API docs.
357         // Note: different from {@link #merge(LineBreakConfig)} if this function is called with
358         // {@link #LINE_BREAK_STYLE_UNSPECIFIED}, the line break style is reset to
359         // {@link #LINE_BREAK_STYLE_UNSPECIFIED}.
360         /**
361          * Sets the line-break style.
362          *
363          * @see <a href="https://unicode.org/reports/tr35/#UnicodeLineBreakStyleIdentifier">
364          *     Unicode Line Break Style Identifier</a>
365          * @see <a href="https://drafts.csswg.org/css-text/#line-break-property">
366          *     CSS Line Break Property</a>
367          *
368          * @param lineBreakStyle The new line-break style.
369          * @return This {@code Builder}.
370          */
setLineBreakStyle(@ineBreakStyle int lineBreakStyle)371         public @NonNull Builder setLineBreakStyle(@LineBreakStyle int lineBreakStyle) {
372             mLineBreakStyle = lineBreakStyle;
373             return this;
374         }
375 
376         // TODO(316208691): Revive following removed API docs.
377         // Note: different from {@link #merge(LineBreakConfig)} method, if this function is called
378         // with {@link #LINE_BREAK_WORD_STYLE_UNSPECIFIED}, the line break style is reset to
379         // {@link #LINE_BREAK_WORD_STYLE_UNSPECIFIED}.
380         /**
381          * Sets the line-break word style.
382          *
383          * @see <a href="https://unicode.org/reports/tr35/#UnicodeLineBreakWordIdentifier">
384          *     Unicode Line Break Word Identifier</a>
385          * @see <a href="https://drafts.csswg.org/css-text/#word-break-property">
386          *     CSS Word Break Property</a>
387          *
388          * @param lineBreakWordStyle The new line-break word style.
389          * @return This {@code Builder}.
390          */
setLineBreakWordStyle(@ineBreakWordStyle int lineBreakWordStyle)391         public @NonNull Builder setLineBreakWordStyle(@LineBreakWordStyle int lineBreakWordStyle) {
392             mLineBreakWordStyle = lineBreakWordStyle;
393             return this;
394         }
395 
396         /**
397          * Sets the hyphenation preference
398          *
399          * Note: Even if the {@link LineBreakConfig#HYPHENATION_ENABLED} is specified, the
400          * hyphenation will not be performed if the {@link android.widget.TextView} or underlying
401          * {@link android.text.StaticLayout}, {@link LineBreaker} are configured with
402          * {@link LineBreaker#HYPHENATION_FREQUENCY_NONE}.
403          *
404          * Note: Even if the hyphenation is enabled with a line break strategy
405          * {@link LineBreaker#BREAK_STRATEGY_SIMPLE}, the hyphenation will not be performed unless a
406          * single word cannot meet width constraints.
407          *
408          * @param hyphenation The hyphenation preference.
409          * @return This {@code Builder}.
410          */
411         @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
setHyphenation(@yphenation int hyphenation)412         public @NonNull Builder setHyphenation(@Hyphenation int hyphenation) {
413             mHyphenation = hyphenation;
414             return this;
415         }
416 
417         /**
418          * Builds a {@link LineBreakConfig} instance.
419          *
420          * This method can be called multiple times for generating multiple {@link LineBreakConfig}
421          * instances.
422          *
423          * @return The {@code LineBreakConfig} instance.
424          */
build()425         public @NonNull LineBreakConfig build() {
426             return new LineBreakConfig(mLineBreakStyle, mLineBreakWordStyle, mHyphenation);
427         }
428     }
429 
430     /**
431      * Creates a {@code LineBreakConfig} instance with the provided line break
432      * parameters.
433      *
434      * @param lineBreakStyle The line-break style for text wrapping.
435      * @param lineBreakWordStyle The line-break word style for text wrapping.
436      * @return The {@code LineBreakConfig} instance.
437      * @hide
438      */
getLineBreakConfig(@ineBreakStyle int lineBreakStyle, @LineBreakWordStyle int lineBreakWordStyle)439     public static @NonNull LineBreakConfig getLineBreakConfig(@LineBreakStyle int lineBreakStyle,
440             @LineBreakWordStyle int lineBreakWordStyle) {
441         LineBreakConfig.Builder builder = new LineBreakConfig.Builder();
442         return builder.setLineBreakStyle(lineBreakStyle)
443                 .setLineBreakWordStyle(lineBreakWordStyle)
444                 .build();
445     }
446 
447     /** @hide */
448     public static final LineBreakConfig NONE =
449             new Builder().setLineBreakStyle(LINE_BREAK_STYLE_NONE)
450                     .setLineBreakWordStyle(LINE_BREAK_WORD_STYLE_NONE).build();
451 
452     private final @LineBreakStyle int mLineBreakStyle;
453     private final @LineBreakWordStyle int mLineBreakWordStyle;
454     private final @Hyphenation int mHyphenation;
455 
456     /**
457      * Constructor with line-break parameters.
458      *
459      * <p>Use {@link LineBreakConfig.Builder} to create the
460      * {@code LineBreakConfig} instance.
461      * @hide
462      */
LineBreakConfig(@ineBreakStyle int lineBreakStyle, @LineBreakWordStyle int lineBreakWordStyle, @Hyphenation int hyphenation)463     public LineBreakConfig(@LineBreakStyle int lineBreakStyle,
464             @LineBreakWordStyle int lineBreakWordStyle,
465             @Hyphenation int hyphenation) {
466         mLineBreakStyle = lineBreakStyle;
467         mLineBreakWordStyle = lineBreakWordStyle;
468         mHyphenation = hyphenation;
469     }
470 
471     /**
472      * Gets the current line-break style.
473      *
474      * @return The line-break style to be used for text wrapping.
475      */
getLineBreakStyle()476     public @LineBreakStyle int getLineBreakStyle() {
477         return mLineBreakStyle;
478     }
479 
480     /**
481      * Gets the resolved line break style.
482      *
483      * This method never returns {@link #LINE_BREAK_STYLE_UNSPECIFIED}.
484      *
485      * @return The line break style.
486      * @hide
487      */
getResolvedLineBreakStyle(@ullable LineBreakConfig config)488     public static @LineBreakStyle int getResolvedLineBreakStyle(@Nullable LineBreakConfig config) {
489         final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
490         final int defaultStyle;
491         final int vicVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM;
492         if (targetSdkVersion >= vicVersion) {
493             defaultStyle = LINE_BREAK_STYLE_AUTO;
494         } else {
495             defaultStyle = LINE_BREAK_STYLE_NONE;
496         }
497         if (config == null) {
498             return defaultStyle;
499         }
500         return config.mLineBreakStyle == LINE_BREAK_STYLE_UNSPECIFIED
501                 ? defaultStyle : config.mLineBreakStyle;
502     }
503 
504     /**
505      * Gets the current line-break word style.
506      *
507      * @return The line-break word style to be used for text wrapping.
508      */
getLineBreakWordStyle()509     public @LineBreakWordStyle int getLineBreakWordStyle() {
510         return mLineBreakWordStyle;
511     }
512 
513     /**
514      * Gets the resolved line break style.
515      *
516      * This method never returns {@link #LINE_BREAK_WORD_STYLE_UNSPECIFIED}.
517      *
518      * @return The line break word style.
519      * @hide
520      */
getResolvedLineBreakWordStyle( @ullable LineBreakConfig config)521     public static @LineBreakWordStyle int getResolvedLineBreakWordStyle(
522             @Nullable LineBreakConfig config) {
523         final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
524         final int defaultWordStyle;
525         final int vicVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM;
526         if (targetSdkVersion >= vicVersion) {
527             defaultWordStyle = LINE_BREAK_WORD_STYLE_AUTO;
528         } else {
529             defaultWordStyle = LINE_BREAK_WORD_STYLE_NONE;
530         }
531         if (config == null) {
532             return defaultWordStyle;
533         }
534         return config.mLineBreakWordStyle == LINE_BREAK_WORD_STYLE_UNSPECIFIED
535                 ? defaultWordStyle : config.mLineBreakWordStyle;
536     }
537 
538     /**
539      * Returns a hyphenation preference.
540      *
541      * @return A hyphenation preference.
542      */
543     @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
getHyphenation()544     public @Hyphenation  int getHyphenation() {
545         return mHyphenation;
546     }
547 
548     /**
549      * Returns a hyphenation preference.
550      *
551      * This method never returns {@link #HYPHENATION_UNSPECIFIED}.
552      *
553      * @return A hyphenation preference.
554      * @hide
555      */
getResolvedHyphenation( @ullable LineBreakConfig config)556     public static @Hyphenation int getResolvedHyphenation(
557             @Nullable LineBreakConfig config) {
558         if (config == null) {
559             return HYPHENATION_ENABLED;
560         }
561         return config.mHyphenation == HYPHENATION_UNSPECIFIED
562                 ? HYPHENATION_ENABLED : config.mHyphenation;
563     }
564 
565 
566     /**
567      * Generates a new {@link LineBreakConfig} instance merged with given {@code config}.
568      *
569      * If values of passing {@code config} are unspecified, the original values are kept. For
570      * example, the following code shows how line break config is merged.
571      *
572      * <pre>
573      *     val override = LineBreakConfig.Builder()
574      *          .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
575      *          .build();  // UNSPECIFIED if no setLineBreakStyle is called.
576      *     val config = LineBreakConfig.Builder()
577      *          .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_STRICT)
578      *          .build();
579      *
580      *     val newConfig = config.merge(override)
581      *     // newConfig has LINE_BREAK_STYLE_STRICT of line break style and
582      *     LINE_BREAK_WORD_STYLE_PHRASE of line break word style.
583      * </pre>
584      *
585      * @param config an overriding config.
586      * @return newly created instance that is current style merged with passed config.
587      */
588     @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
merge(@onNull LineBreakConfig config)589     public @NonNull LineBreakConfig merge(@NonNull LineBreakConfig config) {
590         return new LineBreakConfig(
591                 config.mLineBreakStyle == LINE_BREAK_STYLE_UNSPECIFIED
592                         ? mLineBreakStyle : config.mLineBreakStyle,
593                 config.mLineBreakWordStyle == LINE_BREAK_WORD_STYLE_UNSPECIFIED
594                         ? mLineBreakWordStyle : config.mLineBreakWordStyle,
595                 config.mHyphenation == HYPHENATION_UNSPECIFIED
596                         ? mHyphenation : config.mHyphenation);
597     }
598 
599     @Override
equals(Object o)600     public boolean equals(Object o) {
601         if (o == null) return false;
602         if (this == o) return true;
603         if (!(o instanceof LineBreakConfig)) return false;
604         LineBreakConfig that = (LineBreakConfig) o;
605         return (mLineBreakStyle == that.mLineBreakStyle)
606                 && (mLineBreakWordStyle == that.mLineBreakWordStyle)
607                 && (mHyphenation == that.mHyphenation);
608     }
609 
610     @Override
hashCode()611     public int hashCode() {
612         return Objects.hash(mLineBreakStyle, mLineBreakWordStyle, mHyphenation);
613     }
614 
615     @Override
toString()616     public String toString() {
617         return "LineBreakConfig{"
618                 + "mLineBreakStyle=" + mLineBreakStyle
619                 + ", mLineBreakWordStyle=" + mLineBreakWordStyle
620                 + ", mHyphenation= " + mHyphenation
621                 + '}';
622     }
623 
624     @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
625     @Override
describeContents()626     public int describeContents() {
627         return 0;
628     }
629 
630     @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
631     @Override
writeToParcel(@onNull Parcel dest, int flags)632     public void writeToParcel(@NonNull Parcel dest, int flags) {
633         dest.writeInt(mLineBreakStyle);
634         dest.writeInt(mLineBreakWordStyle);
635         dest.writeInt(mHyphenation);
636     }
637 
638     @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
639     public static final @NonNull Creator<LineBreakConfig> CREATOR = new Creator<>() {
640 
641         @Override
642         public LineBreakConfig createFromParcel(Parcel source) {
643             final int lineBreakStyle = source.readInt();
644             final int lineBreakWordStyle = source.readInt();
645             final int hyphenation = source.readInt();
646             return new LineBreakConfig(lineBreakStyle, lineBreakWordStyle, hyphenation);
647         }
648 
649         @Override
650         public LineBreakConfig[] newArray(int size) {
651             return new LineBreakConfig[size];
652         }
653     };
654 }
655