Fix background and line wrapping in CaptionTextView
Also fixes where two style names were accidentally switched, makes the font sizes larger, and cleans up the CaptionTextView styling APIs in preparation for moving it into the framework. BUG: 10396663 Change-Id: I00999723a67bce2659d913b70dd4420ed32f955c
This commit is contained in:
@@ -27,9 +27,9 @@
|
|||||||
|
|
||||||
<com.android.settings.accessibility.CaptioningTextView
|
<com.android.settings.accessibility.CaptioningTextView
|
||||||
android:id="@+id/preview"
|
android:id="@+id/preview"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:layout_gravity="center"
|
||||||
android:text="@string/captioning_preview_characters" />
|
android:text="@string/captioning_preview_characters" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
@@ -735,11 +735,11 @@
|
|||||||
|
|
||||||
<!-- Values for captioning font size preference. -->
|
<!-- Values for captioning font size preference. -->
|
||||||
<string-array name="captioning_font_size_selector_values" translatable="false" >
|
<string-array name="captioning_font_size_selector_values" translatable="false" >
|
||||||
<item>6.0</item>
|
|
||||||
<item>12.0</item>
|
<item>12.0</item>
|
||||||
<item>24.0</item>
|
<item>24.0</item>
|
||||||
<item>32.0</item>
|
|
||||||
<item>48.0</item>
|
<item>48.0</item>
|
||||||
|
<item>72.0</item>
|
||||||
|
<item>96.0</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<!-- Titles for captioning character edge type preference. [CHAR LIMIT=35] -->
|
<!-- Titles for captioning character edge type preference. [CHAR LIMIT=35] -->
|
||||||
@@ -854,8 +854,8 @@
|
|||||||
|
|
||||||
<!-- Titles for captioning text style preset preference. [CHAR LIMIT=35] -->
|
<!-- Titles for captioning text style preset preference. [CHAR LIMIT=35] -->
|
||||||
<string-array name="captioning_preset_selector_titles" >
|
<string-array name="captioning_preset_selector_titles" >
|
||||||
<item>Black on white</item>
|
|
||||||
<item>White on black</item>
|
<item>White on black</item>
|
||||||
|
<item>Black on white</item>
|
||||||
<item>Yellow on black</item>
|
<item>Yellow on black</item>
|
||||||
<item>Yellow on blue</item>
|
<item>Yellow on blue</item>
|
||||||
<item>Custom</item>
|
<item>Custom</item>
|
||||||
|
@@ -18,51 +18,273 @@ package com.android.settings.accessibility;
|
|||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.Resources.Theme;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Paint.Cap;
|
|
||||||
import android.graphics.Paint.Join;
|
import android.graphics.Paint.Join;
|
||||||
import android.graphics.Paint.Style;
|
import android.graphics.Paint.Style;
|
||||||
import android.os.Parcel;
|
import android.graphics.RectF;
|
||||||
import android.support.v4.view.ViewCompat;
|
import android.graphics.Typeface;
|
||||||
import android.text.Editable;
|
import android.text.Layout.Alignment;
|
||||||
import android.text.ParcelableSpan;
|
import android.text.StaticLayout;
|
||||||
import android.text.TextPaint;
|
import android.text.TextPaint;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.style.CharacterStyle;
|
|
||||||
import android.text.style.UpdateAppearance;
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.accessibility.CaptioningManager;
|
import android.util.DisplayMetrics;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
import android.view.View;
|
||||||
import android.view.accessibility.CaptioningManager.CaptionStyle;
|
import android.view.accessibility.CaptioningManager.CaptionStyle;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
public class CaptioningTextView extends TextView {
|
public class CaptioningTextView extends View {
|
||||||
private MutableBackgroundColorSpan mBackgroundSpan;
|
// Ratio of inner padding to font size.
|
||||||
private ColorStateList mOutlineColorState;
|
private static final float INNER_PADDING_RATIO = 0.125f;
|
||||||
private float mOutlineWidth;
|
|
||||||
private int mOutlineColor;
|
|
||||||
|
|
||||||
private int mEdgeType = CaptionStyle.EDGE_TYPE_NONE;
|
// Default style dimensions in dips.
|
||||||
private int mEdgeColor = Color.TRANSPARENT;
|
private static final float CORNER_RADIUS = 2.0f;
|
||||||
private float mEdgeWidth = 0;
|
private static final float OUTLINE_WIDTH = 2.0f;
|
||||||
|
private static final float SHADOW_RADIUS = 2.0f;
|
||||||
|
private static final float SHADOW_OFFSET_X = 2.0f;
|
||||||
|
private static final float SHADOW_OFFSET_Y = 2.0f;
|
||||||
|
|
||||||
private boolean mHasBackground = false;
|
// Styled dimensions.
|
||||||
|
private final float mCornerRadius;
|
||||||
|
private final float mOutlineWidth;
|
||||||
|
private final float mShadowRadius;
|
||||||
|
private final float mShadowOffsetX;
|
||||||
|
private final float mShadowOffsetY;
|
||||||
|
|
||||||
public CaptioningTextView(Context context, AttributeSet attrs, int defStyle) {
|
/** Temporary rectangle used for computing line bounds. */
|
||||||
super(context, attrs, defStyle);
|
private final RectF mLineBounds = new RectF();
|
||||||
}
|
|
||||||
|
/** Temporary array used for computing line wrapping. */
|
||||||
|
private float[] mTextWidths;
|
||||||
|
|
||||||
|
/** Reusable string builder used for holding text. */
|
||||||
|
private final StringBuilder mText = new StringBuilder();
|
||||||
|
private final StringBuilder mBreakText = new StringBuilder();
|
||||||
|
|
||||||
|
private TextPaint mPaint;
|
||||||
|
|
||||||
|
private int mForegroundColor;
|
||||||
|
private int mBackgroundColor;
|
||||||
|
private int mEdgeColor;
|
||||||
|
private int mEdgeType;
|
||||||
|
|
||||||
|
private boolean mHasMeasurements;
|
||||||
|
private int mLastMeasuredWidth;
|
||||||
|
private StaticLayout mLayout;
|
||||||
|
|
||||||
|
private float mSpacingMult = 1;
|
||||||
|
private float mSpacingAdd = 0;
|
||||||
|
private int mInnerPaddingX = 0;
|
||||||
|
|
||||||
public CaptioningTextView(Context context, AttributeSet attrs) {
|
public CaptioningTextView(Context context, AttributeSet attrs) {
|
||||||
|
this(context, attrs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CaptioningTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
|
||||||
|
final Theme theme = context.getTheme();
|
||||||
|
final TypedArray a = theme.obtainStyledAttributes(
|
||||||
|
attrs, android.R.styleable.TextView, defStyle, 0);
|
||||||
|
|
||||||
|
CharSequence text = "";
|
||||||
|
int textSize = 15;
|
||||||
|
|
||||||
|
final int n = a.getIndexCount();
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int attr = a.getIndex(i);
|
||||||
|
|
||||||
|
switch (attr) {
|
||||||
|
case android.R.styleable.TextView_text:
|
||||||
|
text = a.getText(attr);
|
||||||
|
break;
|
||||||
|
case android.R.styleable.TextView_lineSpacingExtra:
|
||||||
|
mSpacingAdd = a.getDimensionPixelSize(attr, (int) mSpacingAdd);
|
||||||
|
break;
|
||||||
|
case android.R.styleable.TextView_lineSpacingMultiplier:
|
||||||
|
mSpacingMult = a.getFloat(attr, mSpacingMult);
|
||||||
|
break;
|
||||||
|
case android.R.styleable.TextAppearance_textSize:
|
||||||
|
textSize = a.getDimensionPixelSize(attr, textSize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up density-dependent properties.
|
||||||
|
// TODO: Move these to a default style.
|
||||||
|
final DisplayMetrics m = getContext().getResources().getDisplayMetrics();
|
||||||
|
mCornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, m);
|
||||||
|
mOutlineWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, OUTLINE_WIDTH, m);
|
||||||
|
mShadowRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, SHADOW_RADIUS, m);
|
||||||
|
mShadowOffsetX = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, SHADOW_OFFSET_Y, m);
|
||||||
|
mShadowOffsetY = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, SHADOW_OFFSET_X, m);
|
||||||
|
|
||||||
|
final TextPaint paint = new TextPaint();
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
paint.setSubpixelText(true);
|
||||||
|
|
||||||
|
mPaint = paint;
|
||||||
|
|
||||||
|
setText(text);
|
||||||
|
setTextSize(textSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CaptioningTextView(Context context) {
|
public void setText(int resId) {
|
||||||
super(context);
|
final CharSequence text = getContext().getText(resId);
|
||||||
|
setText(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void applyStyleAndFontSize(int styleId) {
|
public void setText(CharSequence text) {
|
||||||
|
mText.setLength(0);
|
||||||
|
mText.append(text);
|
||||||
|
|
||||||
|
mHasMeasurements = false;
|
||||||
|
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForegroundColor(int color) {
|
||||||
|
mForegroundColor = color;
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBackgroundColor(int color) {
|
||||||
|
mBackgroundColor = color;
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEdgeType(int edgeType) {
|
||||||
|
mEdgeType = edgeType;
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEdgeColor(int color) {
|
||||||
|
mEdgeColor = color;
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTextSize(float size) {
|
||||||
|
final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
|
||||||
|
final float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size, metrics);
|
||||||
|
if (mPaint.getTextSize() != size) {
|
||||||
|
mHasMeasurements = false;
|
||||||
|
mInnerPaddingX = (int) (size * INNER_PADDING_RATIO + 0.5f);
|
||||||
|
mPaint.setTextSize(size);
|
||||||
|
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeface(Typeface typeface) {
|
||||||
|
if (mPaint.getTypeface() != typeface) {
|
||||||
|
mHasMeasurements = false;
|
||||||
|
mPaint.setTypeface(typeface);
|
||||||
|
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
final int widthSpec = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
|
||||||
|
if (computeMeasurements(widthSpec)) {
|
||||||
|
final StaticLayout layout = mLayout;
|
||||||
|
|
||||||
|
// Account for padding.
|
||||||
|
final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX * 2;
|
||||||
|
final int width = layout.getWidth() + paddingX;
|
||||||
|
final int height = layout.getHeight() + mPaddingTop + mPaddingBottom;
|
||||||
|
setMeasuredDimension(width, height);
|
||||||
|
} else {
|
||||||
|
setMeasuredDimension(MEASURED_STATE_TOO_SMALL, MEASURED_STATE_TOO_SMALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||||
|
final int width = r - l;
|
||||||
|
|
||||||
|
computeMeasurements(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean computeMeasurements(int maxWidth) {
|
||||||
|
if (mHasMeasurements && maxWidth == mLastMeasuredWidth) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account for padding.
|
||||||
|
final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX;
|
||||||
|
maxWidth -= paddingX;
|
||||||
|
|
||||||
|
if (maxWidth <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final TextPaint paint = mPaint;
|
||||||
|
final CharSequence text = mText;
|
||||||
|
final int textLength = text.length();
|
||||||
|
if (mTextWidths == null || mTextWidths.length < textLength) {
|
||||||
|
mTextWidths = new float[textLength];
|
||||||
|
}
|
||||||
|
|
||||||
|
final float[] textWidths = mTextWidths;
|
||||||
|
paint.getTextWidths(text, 0, textLength, textWidths);
|
||||||
|
|
||||||
|
// Compute total length.
|
||||||
|
float runLength = 0;
|
||||||
|
for (int i = 0; i < textLength; i++) {
|
||||||
|
runLength += textWidths[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
final int lineCount = (int) (runLength / maxWidth) + 1;
|
||||||
|
final int lineLength = (int) (runLength / lineCount);
|
||||||
|
|
||||||
|
// Build line break buffer.
|
||||||
|
final StringBuilder breakText = mBreakText;
|
||||||
|
breakText.setLength(0);
|
||||||
|
|
||||||
|
int line = 0;
|
||||||
|
int lastBreak = 0;
|
||||||
|
int maxRunLength = 0;
|
||||||
|
runLength = 0;
|
||||||
|
for (int i = 0; i < textLength; i++) {
|
||||||
|
if (runLength > lineLength) {
|
||||||
|
final CharSequence sequence = text.subSequence(lastBreak, i);
|
||||||
|
final int trimmedLength = TextUtils.getTrimmedLength(sequence);
|
||||||
|
breakText.append(sequence, 0, trimmedLength);
|
||||||
|
breakText.append('\n');
|
||||||
|
lastBreak = i;
|
||||||
|
runLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
runLength += textWidths[i];
|
||||||
|
|
||||||
|
if (runLength > maxRunLength) {
|
||||||
|
maxRunLength = (int) Math.ceil(runLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
breakText.append(text.subSequence(lastBreak, textLength));
|
||||||
|
|
||||||
|
mHasMeasurements = true;
|
||||||
|
mLastMeasuredWidth = maxWidth;
|
||||||
|
|
||||||
|
mLayout = new StaticLayout(breakText, paint, maxRunLength, Alignment.ALIGN_LEFT,
|
||||||
|
mSpacingMult, mSpacingAdd, true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStyle(int styleId) {
|
||||||
final Context context = mContext;
|
final Context context = mContext;
|
||||||
final ContentResolver cr = context.getContentResolver();
|
final ContentResolver cr = context.getContentResolver();
|
||||||
final CaptionStyle style;
|
final CaptionStyle style;
|
||||||
@@ -72,238 +294,77 @@ public class CaptioningTextView extends TextView {
|
|||||||
style = CaptionStyle.PRESETS[styleId];
|
style = CaptionStyle.PRESETS[styleId];
|
||||||
}
|
}
|
||||||
|
|
||||||
setTextColor(style.foregroundColor);
|
mForegroundColor = style.foregroundColor;
|
||||||
setBackgroundColor(style.backgroundColor);
|
mBackgroundColor = style.backgroundColor;
|
||||||
setTypeface(style.getTypeface());
|
mEdgeType = style.edgeType;
|
||||||
|
mEdgeColor = style.edgeColor;
|
||||||
|
mHasMeasurements = false;
|
||||||
|
|
||||||
// Clears all outlines.
|
final Typeface typeface = style.getTypeface();
|
||||||
applyEdge(style.edgeType, style.edgeColor, 4.0f);
|
setTypeface(typeface);
|
||||||
|
|
||||||
final float fontSize = CaptioningManager.getFontSize(cr);
|
requestLayout();
|
||||||
if (fontSize != 0) {
|
|
||||||
setTextSize(fontSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies an edge preset using a combination of {@link #setOutlineLayer}
|
|
||||||
* and {@link #setShadowLayer}. Any subsequent calls to either of these
|
|
||||||
* methods will invalidate the applied preset.
|
|
||||||
*
|
|
||||||
* @param type Type of edge to apply, one of:
|
|
||||||
* <ul>
|
|
||||||
* <li>{@link CaptionStyle#EDGE_TYPE_NONE}
|
|
||||||
* <li>{@link CaptionStyle#EDGE_TYPE_OUTLINE}
|
|
||||||
* <li>{@link CaptionStyle#EDGE_TYPE_DROP_SHADOW}
|
|
||||||
* </ul>
|
|
||||||
* @param color Edge color as a packed 32-bit ARGB color.
|
|
||||||
* @param width Width of the edge in pixels.
|
|
||||||
*/
|
|
||||||
public void applyEdge(int type, int color, float width) {
|
|
||||||
if (mEdgeType != type || mEdgeColor != color || mEdgeWidth != width) {
|
|
||||||
final int textColor = getTextColors().getDefaultColor();
|
|
||||||
switch (type) {
|
|
||||||
case CaptionStyle.EDGE_TYPE_DROP_SHADOW:
|
|
||||||
setOutlineLayer(0, 0);
|
|
||||||
super.setShadowLayer(width, width, width, color);
|
|
||||||
break;
|
|
||||||
case CaptionStyle.EDGE_TYPE_OUTLINE:
|
|
||||||
setOutlineLayer(width, color);
|
|
||||||
super.setShadowLayer(0, 0, 0, 0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
super.setShadowLayer(0, 0, 0, 0);
|
|
||||||
setOutlineLayer(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
mEdgeType = type;
|
|
||||||
mEdgeColor = color;
|
|
||||||
mEdgeWidth = width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setShadowLayer(float radius, float dx, float dy, int color) {
|
|
||||||
mEdgeType = CaptionStyle.EDGE_TYPE_NONE;
|
|
||||||
|
|
||||||
super.setShadowLayer(radius, dx, dy, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gives the text an outline of the specified pixel width and color.
|
|
||||||
*/
|
|
||||||
public void setOutlineLayer(float width, int color) {
|
|
||||||
width *= 2.0f;
|
|
||||||
|
|
||||||
mEdgeType = CaptionStyle.EDGE_TYPE_NONE;
|
|
||||||
|
|
||||||
if (mOutlineColor != color || mOutlineWidth != width) {
|
|
||||||
mOutlineColorState = ColorStateList.valueOf(color);
|
|
||||||
mOutlineColor = color;
|
|
||||||
mOutlineWidth = width;
|
|
||||||
invalidate();
|
|
||||||
|
|
||||||
// TODO: Remove after display list bug is fixed.
|
|
||||||
if (width > 0 && Color.alpha(color) != 0) {
|
|
||||||
setLayerType(ViewCompat.LAYER_TYPE_SOFTWARE, null);
|
|
||||||
} else {
|
|
||||||
setLayerType(ViewCompat.LAYER_TYPE_HARDWARE, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the color of the outline layer
|
|
||||||
* @see #setOutlineLayer(float, int)
|
|
||||||
*/
|
|
||||||
public int getOutlineColor() {
|
|
||||||
return mOutlineColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the width of the outline layer
|
|
||||||
* @see #setOutlineLayer(float, int)
|
|
||||||
*/
|
|
||||||
public float getOutlineWidth() {
|
|
||||||
return mOutlineWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Editable getEditableText() {
|
|
||||||
final CharSequence text = getText();
|
|
||||||
if (text instanceof Editable) {
|
|
||||||
return (Editable) text;
|
|
||||||
}
|
|
||||||
|
|
||||||
setText(text, BufferType.EDITABLE);
|
|
||||||
return (Editable) getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBackgroundColor(int color) {
|
|
||||||
if (Color.alpha(color) == 0) {
|
|
||||||
if (mHasBackground) {
|
|
||||||
mHasBackground = false;
|
|
||||||
getEditableText().removeSpan(mBackgroundSpan);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (mBackgroundSpan == null) {
|
|
||||||
mBackgroundSpan = new MutableBackgroundColorSpan(color);
|
|
||||||
} else {
|
|
||||||
mBackgroundSpan.setColor(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mHasBackground) {
|
|
||||||
invalidate();
|
|
||||||
} else {
|
|
||||||
mHasBackground = true;
|
|
||||||
getEditableText().setSpan(mBackgroundSpan, 0, length(), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
|
|
||||||
super.onTextChanged(text, start, lengthBefore, lengthAfter);
|
|
||||||
|
|
||||||
if (mBackgroundSpan != null) {
|
|
||||||
getEditableText().setSpan(mBackgroundSpan, 0, lengthAfter, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDraw(Canvas c) {
|
protected void onDraw(Canvas c) {
|
||||||
if (mOutlineWidth > 0 && Color.alpha(mOutlineColor) > 0) {
|
final StaticLayout layout = mLayout;
|
||||||
final TextPaint textPaint = getPaint();
|
if (layout == null) {
|
||||||
final Paint.Style previousStyle = textPaint.getStyle();
|
return;
|
||||||
final ColorStateList previousColors = getTextColors();
|
}
|
||||||
textPaint.setStyle(Style.STROKE);
|
|
||||||
textPaint.setStrokeWidth(mOutlineWidth);
|
|
||||||
textPaint.setStrokeCap(Cap.ROUND);
|
|
||||||
textPaint.setStrokeJoin(Join.ROUND);
|
|
||||||
|
|
||||||
setTextColor(mOutlineColorState);
|
final int saveCount = c.save();
|
||||||
|
final int innerPaddingX = mInnerPaddingX;
|
||||||
|
c.translate(mPaddingLeft + innerPaddingX, mPaddingTop);
|
||||||
|
|
||||||
// Remove the shadow.
|
final RectF bounds = mLineBounds;
|
||||||
final float shadowRadius = getShadowRadius();
|
final int lineCount = layout.getLineCount();
|
||||||
final float shadowDx = getShadowDx();
|
final Paint paint = layout.getPaint();
|
||||||
final float shadowDy = getShadowDy();
|
paint.setShadowLayer(0, 0, 0, 0);
|
||||||
final int shadowColor = getShadowColor();
|
|
||||||
if (shadowRadius > 0) {
|
final int backgroundColor = mBackgroundColor;
|
||||||
setShadowLayer(0, 0, 0, 0);
|
if (Color.alpha(backgroundColor) > 0) {
|
||||||
|
paint.setColor(backgroundColor);
|
||||||
|
paint.setStyle(Style.FILL);
|
||||||
|
|
||||||
|
final float cornerRadius = mCornerRadius;
|
||||||
|
float previousBottom = layout.getLineTop(0);
|
||||||
|
|
||||||
|
for (int i = 0; i < lineCount; i++) {
|
||||||
|
bounds.left = layout.getLineLeft(i) - innerPaddingX;
|
||||||
|
bounds.right = layout.getLineRight(i) + innerPaddingX;
|
||||||
|
bounds.top = previousBottom;
|
||||||
|
bounds.bottom = layout.getLineBottom(i);
|
||||||
|
|
||||||
|
previousBottom = bounds.bottom;
|
||||||
|
|
||||||
|
c.drawRoundRect(bounds, cornerRadius, cornerRadius, paint);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Draw outline and background only.
|
final int edgeType = mEdgeType;
|
||||||
super.onDraw(c);
|
if (edgeType == CaptionStyle.EDGE_TYPE_OUTLINE) {
|
||||||
|
paint.setColor(mEdgeColor);
|
||||||
|
paint.setStyle(Style.FILL_AND_STROKE);
|
||||||
|
paint.setStrokeJoin(Join.ROUND);
|
||||||
|
paint.setStrokeWidth(mOutlineWidth);
|
||||||
|
|
||||||
// Restore the shadow.
|
for (int i = 0; i < lineCount; i++) {
|
||||||
if (shadowRadius > 0) {
|
layout.drawText(c, i, i);
|
||||||
setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore original settings.
|
|
||||||
textPaint.setStyle(previousStyle);
|
|
||||||
setTextColor(previousColors);
|
|
||||||
|
|
||||||
// Remove the background.
|
|
||||||
final int color;
|
|
||||||
if (mBackgroundSpan != null) {
|
|
||||||
color = mBackgroundSpan.getBackgroundColor();
|
|
||||||
mBackgroundSpan.setColor(Color.TRANSPARENT);
|
|
||||||
} else {
|
|
||||||
color = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw foreground only.
|
|
||||||
super.onDraw(c);
|
|
||||||
|
|
||||||
// Restore the background.
|
|
||||||
if (mBackgroundSpan != null) {
|
|
||||||
mBackgroundSpan.setColor(color);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
super.onDraw(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class MutableBackgroundColorSpan extends CharacterStyle
|
|
||||||
implements UpdateAppearance, ParcelableSpan {
|
|
||||||
private int mColor;
|
|
||||||
|
|
||||||
public MutableBackgroundColorSpan(int color) {
|
|
||||||
mColor = color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MutableBackgroundColorSpan(Parcel src) {
|
if (edgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
|
||||||
mColor = src.readInt();
|
paint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mEdgeColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setColor(int color) {
|
paint.setColor(mForegroundColor);
|
||||||
mColor = color;
|
paint.setStyle(Style.FILL);
|
||||||
|
|
||||||
|
for (int i = 0; i < lineCount; i++) {
|
||||||
|
layout.drawText(c, i, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
c.restoreToCount(saveCount);
|
||||||
public int getSpanTypeId() {
|
|
||||||
return TextUtils.BACKGROUND_COLOR_SPAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int describeContents() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
|
||||||
dest.writeInt(mColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBackgroundColor() {
|
|
||||||
return mColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateDrawState(TextPaint ds) {
|
|
||||||
ds.bgColor = mColor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -50,12 +50,14 @@ public class EdgeTypePreference extends ListDialogPreference {
|
|||||||
protected void onBindListItem(View view, int index) {
|
protected void onBindListItem(View view, int index) {
|
||||||
final float fontSize = CaptioningManager.getFontSize(getContext().getContentResolver());
|
final float fontSize = CaptioningManager.getFontSize(getContext().getContentResolver());
|
||||||
final CaptioningTextView preview = (CaptioningTextView) view.findViewById(R.id.preview);
|
final CaptioningTextView preview = (CaptioningTextView) view.findViewById(R.id.preview);
|
||||||
preview.setTextColor(Color.WHITE);
|
|
||||||
|
preview.setForegroundColor(Color.WHITE);
|
||||||
preview.setBackgroundColor(Color.TRANSPARENT);
|
preview.setBackgroundColor(Color.TRANSPARENT);
|
||||||
preview.setTextSize(fontSize);
|
preview.setTextSize(fontSize);
|
||||||
|
|
||||||
final int value = getValueAt(index);
|
final int value = getValueAt(index);
|
||||||
preview.applyEdge(value, Color.BLACK, 4.0f);
|
preview.setEdgeType(value);
|
||||||
|
preview.setEdgeColor(Color.BLACK);
|
||||||
|
|
||||||
final CharSequence title = getTitleAt(index);
|
final CharSequence title = getTitleAt(index);
|
||||||
if (title != null) {
|
if (title != null) {
|
||||||
|
@@ -86,10 +86,13 @@ public class ToggleCaptioningPreferenceFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void applyCaptionProperties(CaptioningTextView previewText, int styleId) {
|
public static void applyCaptionProperties(CaptioningTextView previewText, int styleId) {
|
||||||
previewText.applyStyleAndFontSize(styleId);
|
previewText.setStyle(styleId);
|
||||||
|
|
||||||
final Context context = previewText.getContext();
|
final Context context = previewText.getContext();
|
||||||
final ContentResolver cr = context.getContentResolver();
|
final ContentResolver cr = context.getContentResolver();
|
||||||
|
final float fontSize = CaptioningManager.getFontSize(cr);
|
||||||
|
previewText.setTextSize(fontSize);
|
||||||
|
|
||||||
final Locale locale = CaptioningManager.getLocale(cr);
|
final Locale locale = CaptioningManager.getLocale(cr);
|
||||||
if (locale != null) {
|
if (locale != null) {
|
||||||
final CharSequence localizedText = AccessibilityUtils.getTextForLocale(
|
final CharSequence localizedText = AccessibilityUtils.getTextForLocale(
|
||||||
|
Reference in New Issue
Block a user