/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package androidx.car.app.model; import static androidx.annotation.RestrictTo.Scope.LIBRARY; import static java.util.Objects.requireNonNull; import android.text.SpannableString; import android.text.Spanned; import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; import androidx.car.app.annotations.CarProtocol; import androidx.car.app.annotations.RequiresCarApi; import androidx.car.app.utils.CollectionUtils; import androidx.car.app.utils.StringUtils; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; /** * A model that represents text to display in the car screen. * *
The Car App Library only supports a specific set of spans of type {@link CarSpan}. Further, * individual APIs in the library that take text as input may only support a certain subset of * {@link CarSpan}s. Spans that are not supported will be simply ignored by the host. * *
By default and unless explicitly documented in the individual APIs that take a text * parameter as input, spans for that API are not supported and will be ignored. * *
For example, the {@link Row.Builder#addText(CharSequence)} API documents that * {@link ForegroundCarColorSpan} instances can be used to color the text of the row. This means any * other types of spans except {@link ForegroundCarColorSpan} will be ignored. * *
{@link CarText} instances represent the text that was passed by the app through a * {@link CharSequence}, with the non-{@link CarSpan} spans removed. * *
The {@link CarText#toString} method can be used to get a string representation of the string, * whereas the {@link CarText#toCharSequence()} method returns the reconstructed * {@link CharSequence}, with the non{@link CarSpan} spans removed. * *
The app is generally agnostic to the width of the views generated by the host that contain
* the text strings it supplies. For that reason, some models that take text allow the app to
* pass a list of text variants of different lengths. In those cases the host will pick the
* variant that best fits the screen. See {@link Builder#addVariant} for more information.
*/
@CarProtocol
public final class CarText {
@Keep
private final String mText;
@Keep
private final List Only {@link CarSpan} type spans are allowed in a {@link CarText}, other spans will be
* removed from the provided {@link CharSequence}.
*
* @throws NullPointerException if the text is {@code null}
*/
@NonNull
public static CarText create(@NonNull CharSequence text) {
return new CarText(requireNonNull(text));
}
/**
* Returns whether the text string is empty.
*
* Only the first variant is checked.
*/
public boolean isEmpty() {
return mText.isEmpty();
}
/**
* Returns the string representation of the {@link CarText}.
*
* Only the first variant is returned.
*/
@NonNull
@Override
public String toString() {
return mText;
}
/**
* Returns the {@link CharSequence} corresponding to the first text variant.
*
* Spans that are not of type {@link CarSpan} that were passed when creating the
* {@link CarText} instance will not be present in the returned {@link CharSequence}.
*
* @see CarText#create(CharSequence)
*/
@NonNull
public CharSequence toCharSequence() {
return getCharSequence(mText, mSpans);
}
/**
* Returns the list of variants for this text.
*
* Only the variants set with {@link Builder#addVariant(CharSequence)} will be returned.
* To get the first variant, use {@link CarText#toCharSequence}.
*
* Spans that are not of type {@link CarSpan} that were passed when creating the
* {@link CarText} instance will not be present in the returned {@link CharSequence}.
*
* @see Builder#addVariant(CharSequence)
*/
@NonNull
public List Only {@link CarSpan} type spans are allowed in a {@link CarText}, other spans will be
* removed from the provided {@link CharSequence}.
*
* @param text the first variant of the text to use. This represents the app's preferred
* text variant. Other alternatives can be supplied with
* {@link Builder#addVariant}.
* @throws NullPointerException if the text is {@code null}
* @see Builder#addVariant(CharSequence)
*/
public Builder(@NonNull CharSequence text) {
mText = requireNonNull(text);
}
/**
* Adds a text variant for the {@link CarText} instance.
*
* Only {@link CarSpan} type spans are allowed in a {@link CarText}, other spans will be
* removed from the provided {@link CharSequence}.
*
* The text variants should be added in order of preference, from most to least
* preferred (for instance, from longest to shortest). If the text provided via
* {@link #Builder} does not fit in the screen, the host will display the
* first variant that fits in the screen.
*
* For instance, if the variant order is ["long string", "shorter", "short"], and the
* screen can fit 7 characters, "shorter" will be chosen. However, if the order is
* ["short", "shorter", "long string"], "short" will be chosen, because "short" fits
* within the 7 character limit.
*
* @throws NullPointerException if the text is {@code null}
*/
@RequiresCarApi(2)
@NonNull
public Builder addVariant(@NonNull CharSequence text) {
mTextVariants.add(requireNonNull(text));
return this;
}
/**
* Constructs the {@link CarText} defined by this builder.
*/
@NonNull
public CarText build() {
return new CarText(this);
}
}
}
> mSpansForVariants;
/**
* Returns {@code true} if the {@code carText} is {@code null} or an empty string, {@code
* false} otherwise.
*/
public static boolean isNullOrEmpty(@Nullable CarText carText) {
return carText == null || carText.isEmpty();
}
/**
* Returns a {@link CarText} instance for the given {@link CharSequence}.
*
*
> getSpansForVariants() {
return mSpansForVariants;
}
/**
* Returns a shortened string from the input {@code text}.
*
* @hide
*/
@RestrictTo(LIBRARY)
@Nullable
public static String toShortString(@Nullable CarText text) {
return text == null ? null : StringUtils.shortenString(text.toString());
}
private CarText() {
mText = "";
mSpans = Collections.emptyList();
mTextVariants = Collections.emptyList();
mSpansForVariants = Collections.emptyList();
}
CarText(CharSequence text) {
mText = text.toString();
mSpans = getSpans(text);
mTextVariants = Collections.emptyList();
mSpansForVariants = Collections.emptyList();
}
CarText(Builder builder) {
mText = builder.mText.toString();
mSpans = getSpans(builder.mText);
List
> spanList = new ArrayList<>();
for (int i = 0; i < textVariants.size(); i++) {
CharSequence text = textVariants.get(i);
textList.add(text.toString());
spanList.add(getSpans(text));
}
mTextVariants = CollectionUtils.unmodifiableCopy(textList);
mSpansForVariants = CollectionUtils.unmodifiableCopy(spanList);
}
private static List