blob: b21d6be37bc2482c75d2574b9b43750eef922708 [file] [log] [blame]
/*
* Copyright (C) 2014 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 com.google.android.exoplayer.text;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.text.Layout.Alignment;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import com.google.android.exoplayer.util.Util;
/**
* Since this class does not exist in recent version of ExoPlayer and used by
* {@link com.android.usbtuner.cc.CaptionWindowLayout}, this class is copied from
* older version of ExoPlayer.
* A view for rendering a single caption.
*/
@Deprecated
public class SubtitleView extends View {
// TODO: Change usage of this class to up-to-date class of ExoPlayer.
/**
* Ratio of inner padding to font size.
*/
private static final float INNER_PADDING_RATIO = 0.125f;
/**
* Temporary rectangle used for computing line bounds.
*/
private final RectF mLineBounds = new RectF();
// Styled dimensions.
private final float mCornerRadius;
private final float mOutlineWidth;
private final float mShadowRadius;
private final float mShadowOffset;
private TextPaint mTextPaint;
private Paint mPaint;
private CharSequence mText;
private int mForegroundColor;
private int mBackgroundColor;
private int mEdgeColor;
private int mEdgeType;
private boolean mHasMeasurements;
private int mLastMeasuredWidth;
private StaticLayout mLayout;
private Alignment mAlignment;
private float mSpacingMult;
private float mSpacingAdd;
private int mInnerPaddingX;
public SubtitleView(Context context) {
this(context, null);
}
public SubtitleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SubtitleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
int[] viewAttr = {android.R.attr.text, android.R.attr.textSize,
android.R.attr.lineSpacingExtra, android.R.attr.lineSpacingMultiplier};
TypedArray a = context.obtainStyledAttributes(attrs, viewAttr, defStyleAttr, 0);
CharSequence text = a.getText(0);
int textSize = a.getDimensionPixelSize(1, 15);
mSpacingAdd = a.getDimensionPixelSize(2, 0);
mSpacingMult = a.getFloat(3, 1);
a.recycle();
Resources resources = getContext().getResources();
DisplayMetrics displayMetrics = resources.getDisplayMetrics();
int twoDpInPx =
Math.round((2f * displayMetrics.densityDpi) / DisplayMetrics.DENSITY_DEFAULT);
mCornerRadius = twoDpInPx;
mOutlineWidth = twoDpInPx;
mShadowRadius = twoDpInPx;
mShadowOffset = twoDpInPx;
mTextPaint = new TextPaint();
mTextPaint.setAntiAlias(true);
mTextPaint.setSubpixelText(true);
mAlignment = Alignment.ALIGN_CENTER;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mInnerPaddingX = 0;
setText(text);
setTextSize(textSize);
setStyle(CaptionStyleCompat.DEFAULT);
}
@Override
public void setBackgroundColor(int color) {
mBackgroundColor = color;
forceUpdate(false);
}
/**
* Sets the text to be displayed by the view.
*
* @param text The text to display.
*/
public void setText(CharSequence text) {
this.mText = text;
forceUpdate(true);
}
/**
* Sets the text size in pixels.
*
* @param size The text size in pixels.
*/
public void setTextSize(float size) {
if (mTextPaint.getTextSize() != size) {
mTextPaint.setTextSize(size);
mInnerPaddingX = (int) (size * INNER_PADDING_RATIO + 0.5f);
forceUpdate(true);
}
}
/**
* Sets the text alignment.
*
* @param textAlignment The text alignment.
*/
public void setTextAlignment(Alignment textAlignment) {
mAlignment = textAlignment;
}
/**
* Configures the view according to the given style.
*
* @param style A style for the view.
*/
public void setStyle(CaptionStyleCompat style) {
mForegroundColor = style.foregroundColor;
mBackgroundColor = style.backgroundColor;
mEdgeType = style.edgeType;
mEdgeColor = style.edgeColor;
setTypeface(style.typeface);
super.setBackgroundColor(style.windowColor);
forceUpdate(true);
}
private void setTypeface(Typeface typeface) {
if (mTextPaint.getTypeface() != typeface) {
mTextPaint.setTypeface(typeface);
forceUpdate(true);
}
}
private void forceUpdate(boolean needsLayout) {
if (needsLayout) {
mHasMeasurements = false;
requestLayout();
}
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthSpec = MeasureSpec.getSize(widthMeasureSpec);
if (computeMeasurements(widthSpec)) {
final StaticLayout layout = this.mLayout;
final int paddingX = getPaddingLeft() + getPaddingRight() + mInnerPaddingX * 2;
final int height = layout.getHeight() + getPaddingTop() + getPaddingBottom();
int width = 0;
int lineCount = layout.getLineCount();
for (int i = 0; i < lineCount; i++) {
width = Math.max((int) Math.ceil(layout.getLineWidth(i)), width);
}
width += paddingX;
setMeasuredDimension(width, height);
} else if (Util.SDK_INT >= 11) {
setTooSmallMeasureDimensionV11();
} else {
setMeasuredDimension(0, 0);
}
}
@TargetApi(11)
private void setTooSmallMeasureDimensionV11() {
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 = getPaddingLeft() + getPaddingRight() + mInnerPaddingX * 2;
maxWidth -= paddingX;
if (maxWidth <= 0) {
return false;
}
mHasMeasurements = true;
mLastMeasuredWidth = maxWidth;
mLayout = new StaticLayout(mText, mTextPaint, maxWidth, mAlignment,
mSpacingMult, mSpacingAdd, true);
return true;
}
@Override
protected void onDraw(Canvas c) {
final StaticLayout layout = this.mLayout;
if (layout == null) {
return;
}
final int saveCount = c.save();
final int innerPaddingX = this.mInnerPaddingX;
c.translate(getPaddingLeft() + innerPaddingX, getPaddingTop());
final int lineCount = layout.getLineCount();
final Paint textPaint = this.mTextPaint;
final Paint paint = this.mPaint;
final RectF bounds = mLineBounds;
if (Color.alpha(mBackgroundColor) > 0) {
final float cornerRadius = this.mCornerRadius;
float previousBottom = layout.getLineTop(0);
paint.setColor(mBackgroundColor);
paint.setStyle(Style.FILL);
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);
}
}
if (mEdgeType == CaptionStyleCompat.EDGE_TYPE_OUTLINE) {
textPaint.setStrokeJoin(Join.ROUND);
textPaint.setStrokeWidth(mOutlineWidth);
textPaint.setColor(mEdgeColor);
textPaint.setStyle(Style.FILL_AND_STROKE);
layout.draw(c);
} else if (mEdgeType == CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW) {
textPaint.setShadowLayer(mShadowRadius, mShadowOffset, mShadowOffset, mEdgeColor);
} else if (mEdgeType == CaptionStyleCompat.EDGE_TYPE_RAISED
|| mEdgeType == CaptionStyleCompat.EDGE_TYPE_DEPRESSED) {
boolean raised = mEdgeType == CaptionStyleCompat.EDGE_TYPE_RAISED;
int colorUp = raised ? Color.WHITE : mEdgeColor;
int colorDown = raised ? mEdgeColor : Color.WHITE;
float offset = mShadowRadius / 2f;
textPaint.setColor(mForegroundColor);
textPaint.setStyle(Style.FILL);
textPaint.setShadowLayer(mShadowRadius, -offset, -offset, colorUp);
layout.draw(c);
textPaint.setShadowLayer(mShadowRadius, offset, offset, colorDown);
}
textPaint.setColor(mForegroundColor);
textPaint.setStyle(Style.FILL);
layout.draw(c);
textPaint.setShadowLayer(0, 0, 0, 0);
c.restoreToCount(saveCount);
}
}