• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 com.android.inputmethod.latin.utils;
18 
19 import android.text.Spannable;
20 import android.text.SpannableString;
21 import android.text.Spanned;
22 import android.text.SpannedString;
23 import android.text.TextUtils;
24 import android.text.style.SuggestionSpan;
25 
26 public final class SpannableStringUtils {
27     /**
28      * Copies the spans from the region <code>start...end</code> in
29      * <code>source</code> to the region
30      * <code>destoff...destoff+end-start</code> in <code>dest</code>.
31      * Spans in <code>source</code> that begin before <code>start</code>
32      * or end after <code>end</code> but overlap this range are trimmed
33      * as if they began at <code>start</code> or ended at <code>end</code>.
34      * Only SuggestionSpans that don't have the SPAN_PARAGRAPH span are copied.
35      *
36      * This code is almost entirely taken from {@link TextUtils#copySpansFrom}, except for the
37      * kind of span that is copied.
38      *
39      * @throws IndexOutOfBoundsException if any of the copied spans
40      * are out of range in <code>dest</code>.
41      */
copyNonParagraphSuggestionSpansFrom(Spanned source, int start, int end, Spannable dest, int destoff)42     public static void copyNonParagraphSuggestionSpansFrom(Spanned source, int start, int end,
43                                      Spannable dest, int destoff) {
44         Object[] spans = source.getSpans(start, end, SuggestionSpan.class);
45 
46         for (int i = 0; i < spans.length; i++) {
47             int fl = source.getSpanFlags(spans[i]);
48             if (0 != (fl & Spannable.SPAN_PARAGRAPH)) continue;
49 
50             int st = source.getSpanStart(spans[i]);
51             int en = source.getSpanEnd(spans[i]);
52 
53             if (st < start)
54                 st = start;
55             if (en > end)
56                 en = end;
57 
58             dest.setSpan(spans[i], st - start + destoff, en - start + destoff,
59                          fl);
60         }
61     }
62 
63     /**
64      * Returns a CharSequence concatenating the specified CharSequences, retaining their
65      * SuggestionSpans that don't have the PARAGRAPH flag, but not other spans.
66      *
67      * This code is almost entirely taken from {@link TextUtils#concat(CharSequence...)}, except
68      * it calls copyNonParagraphSuggestionSpansFrom instead of {@link TextUtils#copySpansFrom}.
69      */
concatWithNonParagraphSuggestionSpansOnly(CharSequence... text)70     public static CharSequence concatWithNonParagraphSuggestionSpansOnly(CharSequence... text) {
71         if (text.length == 0) {
72             return "";
73         }
74 
75         if (text.length == 1) {
76             return text[0];
77         }
78 
79         boolean spanned = false;
80         for (int i = 0; i < text.length; i++) {
81             if (text[i] instanceof Spanned) {
82                 spanned = true;
83                 break;
84             }
85         }
86 
87         StringBuilder sb = new StringBuilder();
88         for (int i = 0; i < text.length; i++) {
89             sb.append(text[i]);
90         }
91 
92         if (!spanned) {
93             return sb.toString();
94         }
95 
96         SpannableString ss = new SpannableString(sb);
97         int off = 0;
98         for (int i = 0; i < text.length; i++) {
99             int len = text[i].length();
100 
101             if (text[i] instanceof Spanned) {
102                 copyNonParagraphSuggestionSpansFrom((Spanned) text[i], 0, len, ss, off);
103             }
104 
105             off += len;
106         }
107 
108         return new SpannedString(ss);
109     }
110 }
111