1 /*
2  * Copyright (C) 2020 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 package com.google.android.exoplayer2.text.span;
17 
18 import android.text.Spannable;
19 import android.text.style.ForegroundColorSpan;
20 
21 /**
22  * Utility methods for Android <a href="https://developer.android.com/guide/topics/text/spans">span
23  * styling</a>.
24  */
25 public final class SpanUtil {
26 
27   /**
28    * Adds {@code span} to {@code spannable} between {@code start} and {@code end}, removing any
29    * existing spans of the same type and with the same indices and flags.
30    *
31    * <p>This is useful for types of spans that don't make sense to duplicate and where the
32    * evaluation order might have an unexpected impact on the final text, e.g. {@link
33    * ForegroundColorSpan}.
34    *
35    * @param spannable The {@link Spannable} to add {@code span} to.
36    * @param span The span object to be added.
37    * @param start The start index to add the new span at.
38    * @param end The end index to add the new span at.
39    * @param spanFlags The flags to pass to {@link Spannable#setSpan(Object, int, int, int)}.
40    */
addOrReplaceSpan( Spannable spannable, Object span, int start, int end, int spanFlags)41   public static void addOrReplaceSpan(
42       Spannable spannable, Object span, int start, int end, int spanFlags) {
43     Object[] existingSpans = spannable.getSpans(start, end, span.getClass());
44     for (Object existingSpan : existingSpans) {
45       if (spannable.getSpanStart(existingSpan) == start
46           && spannable.getSpanEnd(existingSpan) == end
47           && spannable.getSpanFlags(existingSpan) == spanFlags) {
48         spannable.removeSpan(existingSpan);
49       }
50     }
51     spannable.setSpan(span, start, end, spanFlags);
52   }
53 
SpanUtil()54   private SpanUtil() {}
55 }
56