1d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette/* 2d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Copyright (C) 2013 The Android Open Source Project 3d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 4d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Licensed under the Apache License, Version 2.0 (the "License"); 5d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * you may not use this file except in compliance with the License. 6d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * You may obtain a copy of the License at 7d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 8d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * http://www.apache.org/licenses/LICENSE-2.0 9d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 10d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Unless required by applicable law or agreed to in writing, software 11d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * distributed under the License is distributed on an "AS IS" BASIS, 12d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * See the License for the specific language governing permissions and 14d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * limitations under the License. 15d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 16d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarpackage android.media; 1876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 1976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarimport android.content.Context; 207fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viveretteimport android.text.Layout.Alignment; 21d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteimport android.text.SpannableStringBuilder; 22d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteimport android.util.ArrayMap; 2376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarimport android.util.AttributeSet; 2476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarimport android.util.Log; 25d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteimport android.view.Gravity; 2676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarimport android.view.View; 27d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteimport android.view.ViewGroup; 28d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteimport android.view.accessibility.CaptioningManager; 29d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteimport android.view.accessibility.CaptioningManager.CaptionStyle; 30d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteimport android.view.accessibility.CaptioningManager.CaptioningChangeListener; 31d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteimport android.widget.LinearLayout; 32d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 33d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteimport com.android.internal.widget.SubtitleView; 3476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 35d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteimport java.util.ArrayList; 3676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarimport java.util.Arrays; 3776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarimport java.util.HashMap; 3876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarimport java.util.Map; 3976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarimport java.util.Vector; 4076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 4176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar/** @hide */ 4276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarpublic class WebVttRenderer extends SubtitleController.Renderer { 43d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final Context mContext; 4476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 45d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private WebVttRenderingWidget mRenderingWidget; 46d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 47d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public WebVttRenderer(Context context) { 48d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mContext = context; 4976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 5076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 5176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 5276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public boolean supports(MediaFormat format) { 5376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (format.containsKey(MediaFormat.KEY_MIME)) { 5476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return format.getString(MediaFormat.KEY_MIME).equals("text/vtt"); 5576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 5676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return false; 5776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 5876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 5976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 6076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public SubtitleTrack createTrack(MediaFormat format) { 61d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mRenderingWidget == null) { 62d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mRenderingWidget = new WebVttRenderingWidget(mContext); 63d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 6476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 65d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return new WebVttTrack(mRenderingWidget, format); 6676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 6776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 6876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 6976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar/** @hide */ 7076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarclass TextTrackCueSpan { 7176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar long mTimestampMs; 7276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean mEnabled; 7376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String mText; 7476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCueSpan(String text, long timestamp) { 7576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTimestampMs = timestamp; 7676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mText = text; 7776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // spans with timestamp will be enabled by Cue.onTime 7876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mEnabled = (mTimestampMs < 0); 7976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 8076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 8176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 8276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public boolean equals(Object o) { 8376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!(o instanceof TextTrackCueSpan)) { 8476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return false; 8576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 8676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCueSpan span = (TextTrackCueSpan) o; 8776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return mTimestampMs == span.mTimestampMs && 8876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mText.equals(span.mText); 8976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 9076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 9176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 9276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar/** 9376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar * @hide 9476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar * 9576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar * Extract all text without style, but with timestamp spans. 9676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar */ 9776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarclass UnstyledTextExtractor implements Tokenizer.OnTokenListener { 9876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar StringBuilder mLine = new StringBuilder(); 9976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Vector<TextTrackCueSpan[]> mLines = new Vector<TextTrackCueSpan[]>(); 10076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Vector<TextTrackCueSpan> mCurrentLine = new Vector<TextTrackCueSpan>(); 10176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar long mLastTimestamp; 10276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 10376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar UnstyledTextExtractor() { 10476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar init(); 10576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 10676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 10776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private void init() { 10876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLine.delete(0, mLine.length()); 10976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLines.clear(); 11076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCurrentLine.clear(); 11176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLastTimestamp = -1; 11276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 11376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 11476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 11576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void onData(String s) { 11676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLine.append(s); 11776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 11876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 11976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 12076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void onStart(String tag, String[] classes, String annotation) { } 12176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 12276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 12376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void onEnd(String tag) { } 12476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 12576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 12676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void onTimeStamp(long timestampMs) { 12776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // finish any prior span 12876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mLine.length() > 0 && timestampMs != mLastTimestamp) { 12976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCurrentLine.add( 13076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar new TextTrackCueSpan(mLine.toString(), mLastTimestamp)); 13176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLine.delete(0, mLine.length()); 13276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 13376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLastTimestamp = timestampMs; 13476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 13576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 13676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 13776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void onLineEnd() { 13876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // finish any pending span 13976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mLine.length() > 0) { 14076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCurrentLine.add( 14176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar new TextTrackCueSpan(mLine.toString(), mLastTimestamp)); 14276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLine.delete(0, mLine.length()); 14376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 14476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 14576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCueSpan[] spans = new TextTrackCueSpan[mCurrentLine.size()]; 14676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCurrentLine.toArray(spans); 14776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCurrentLine.clear(); 14876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLines.add(spans); 14976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 15076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 15176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public TextTrackCueSpan[][] getText() { 15276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // for politeness, finish last cue-line if it ends abruptly 15376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mLine.length() > 0 || mCurrentLine.size() > 0) { 15476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar onLineEnd(); 15576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 15676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCueSpan[][] lines = new TextTrackCueSpan[mLines.size()][]; 15776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLines.toArray(lines); 15876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar init(); 15976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return lines; 16076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 16176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 16276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 16376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar/** 16476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar * @hide 16576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar * 16676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar * Tokenizer tokenizes the WebVTT Cue Text into tags and data 16776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar */ 16876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarclass Tokenizer { 16976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private static final String TAG = "Tokenizer"; 17076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private TokenizerPhase mPhase; 17176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private TokenizerPhase mDataTokenizer; 17276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private TokenizerPhase mTagTokenizer; 17376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 17476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private OnTokenListener mListener; 17576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private String mLine; 17676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private int mHandledLen; 17776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 17876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar interface TokenizerPhase { 17976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TokenizerPhase start(); 18076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void tokenize(); 18176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 18276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 18376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar class DataTokenizer implements TokenizerPhase { 18476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // includes both WebVTT data && escape state 18576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private StringBuilder mData; 18676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 18776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public TokenizerPhase start() { 18876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mData = new StringBuilder(); 18976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return this; 19076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 19176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 19276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private boolean replaceEscape(String escape, String replacement, int pos) { 19376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mLine.startsWith(escape, pos)) { 19476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mData.append(mLine.substring(mHandledLen, pos)); 19576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mData.append(replacement); 19676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mHandledLen = pos + escape.length(); 19776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar pos = mHandledLen - 1; 19876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return true; 19976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 20076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return false; 20176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 20276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 20376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 20476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void tokenize() { 20576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int end = mLine.length(); 20676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (int pos = mHandledLen; pos < mLine.length(); pos++) { 20776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mLine.charAt(pos) == '&') { 20876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (replaceEscape("&", "&", pos) || 20976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar replaceEscape("<", "<", pos) || 21076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar replaceEscape(">", ">", pos) || 21176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar replaceEscape("‎", "\u200e", pos) || 21276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar replaceEscape("‏", "\u200f", pos) || 21376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar replaceEscape(" ", "\u00a0", pos)) { 21476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 21576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 21676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (mLine.charAt(pos) == '<') { 21776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar end = pos; 21876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mTagTokenizer.start(); 21976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar break; 22076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 22176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 22276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mData.append(mLine.substring(mHandledLen, end)); 22376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // yield mData 22476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mListener.onData(mData.toString()); 22576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mData.delete(0, mData.length()); 22676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mHandledLen = end; 22776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 22876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 22976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 23076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar class TagTokenizer implements TokenizerPhase { 23176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private boolean mAtAnnotation; 23276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private String mName, mAnnotation; 23376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 23476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public TokenizerPhase start() { 23576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mName = mAnnotation = ""; 23676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAtAnnotation = false; 23776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return this; 23876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 23976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 24076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 24176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void tokenize() { 24276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!mAtAnnotation) 24376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mHandledLen++; 24476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mHandledLen < mLine.length()) { 24576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String[] parts; 24676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar /** 24776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar * Collect annotations and end-tags to closing >. Collect tag 24876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar * name to closing bracket or next white-space. 24976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar */ 25076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mAtAnnotation || mLine.charAt(mHandledLen) == '/') { 25176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar parts = mLine.substring(mHandledLen).split(">"); 25276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 25376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar parts = mLine.substring(mHandledLen).split("[\t\f >]"); 25476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 25576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String part = mLine.substring( 25676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mHandledLen, mHandledLen + parts[0].length()); 25776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mHandledLen += parts[0].length(); 25876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 25976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mAtAnnotation) { 26076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAnnotation += " " + part; 26176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 26276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mName = part; 26376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 26476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 26576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 26676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAtAnnotation = true; 26776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 26876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mHandledLen < mLine.length() && mLine.charAt(mHandledLen) == '>') { 26976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar yield_tag(); 27076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mDataTokenizer.start(); 27176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mHandledLen++; 27276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 27376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 27476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 27576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private void yield_tag() { 27676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mName.startsWith("/")) { 27776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mListener.onEnd(mName.substring(1)); 27876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (mName.length() > 0 && Character.isDigit(mName.charAt(0))) { 27976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // timestamp 28076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 28176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar long timestampMs = WebVttParser.parseTimestampMs(mName); 28276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mListener.onTimeStamp(timestampMs); 28376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 28476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Log.d(TAG, "invalid timestamp tag: <" + mName + ">"); 28576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 28676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 28776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAnnotation = mAnnotation.replaceAll("\\s+", " "); 28876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mAnnotation.startsWith(" ")) { 28976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAnnotation = mAnnotation.substring(1); 29076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 29176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mAnnotation.endsWith(" ")) { 29276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAnnotation = mAnnotation.substring(0, mAnnotation.length() - 1); 29376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 29476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 29576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String[] classes = null; 29676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int dotAt = mName.indexOf('.'); 29776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (dotAt >= 0) { 29876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar classes = mName.substring(dotAt + 1).split("\\."); 29976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mName = mName.substring(0, dotAt); 30076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 30176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mListener.onStart(mName, classes, mAnnotation); 30276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 30376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 30476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 30576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 30676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Tokenizer(OnTokenListener listener) { 30776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mDataTokenizer = new DataTokenizer(); 30876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTagTokenizer = new TagTokenizer(); 30976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar reset(); 31076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mListener = listener; 31176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 31276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 31376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void reset() { 31476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mDataTokenizer.start(); 31576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 31676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 31776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void tokenize(String s) { 31876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mHandledLen = 0; 31976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLine = s; 32076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar while (mHandledLen < mLine.length()) { 32176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase.tokenize(); 32276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 32376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar /* we are finished with a line unless we are in the middle of a tag */ 32476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!(mPhase instanceof TagTokenizer)) { 32576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // yield END-OF-LINE 32676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mListener.onLineEnd(); 32776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 32876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 32976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 33076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar interface OnTokenListener { 33176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void onData(String s); 33276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void onStart(String tag, String[] classes, String annotation); 33376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void onEnd(String tag); 33476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void onTimeStamp(long timestampMs); 33576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void onLineEnd(); 33676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 33776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 33876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 33976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar/** @hide */ 34076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarclass TextTrackRegion { 34176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final static int SCROLL_VALUE_NONE = 300; 34276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final static int SCROLL_VALUE_SCROLL_UP = 301; 34376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 34476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String mId; 34576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar float mWidth; 34676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int mLines; 34776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar float mAnchorPointX, mAnchorPointY; 34876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar float mViewportAnchorPointX, mViewportAnchorPointY; 34976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int mScrollValue; 35076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 35176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackRegion() { 35276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mId = ""; 35376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mWidth = 100; 35476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLines = 3; 35576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAnchorPointX = mViewportAnchorPointX = 0.f; 35676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAnchorPointY = mViewportAnchorPointY = 100.f; 35776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mScrollValue = SCROLL_VALUE_NONE; 35876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 35976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 36076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public String toString() { 36176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar StringBuilder res = new StringBuilder(" {id:\"").append(mId) 36276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append("\", width:").append(mWidth) 36376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", lines:").append(mLines) 36476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", anchorPoint:(").append(mAnchorPointX) 36576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", ").append(mAnchorPointY) 36676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append("), viewportAnchorPoints:").append(mViewportAnchorPointX) 36776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", ").append(mViewportAnchorPointY) 36876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append("), scrollValue:") 36976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(mScrollValue == SCROLL_VALUE_NONE ? "none" : 37076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mScrollValue == SCROLL_VALUE_SCROLL_UP ? "scroll_up" : 37176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "INVALID") 37276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append("}"); 37376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return res.toString(); 37476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 37576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 37676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 37776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar/** @hide */ 37876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarclass TextTrackCue extends SubtitleTrack.Cue { 37976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final static int WRITING_DIRECTION_HORIZONTAL = 100; 38076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final static int WRITING_DIRECTION_VERTICAL_RL = 101; 38176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final static int WRITING_DIRECTION_VERTICAL_LR = 102; 38276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 38376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final static int ALIGNMENT_MIDDLE = 200; 38476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final static int ALIGNMENT_START = 201; 38576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final static int ALIGNMENT_END = 202; 38676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final static int ALIGNMENT_LEFT = 203; 38776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final static int ALIGNMENT_RIGHT = 204; 38876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private static final String TAG = "TTCue"; 38976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 39076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String mId; 39176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean mPauseOnExit; 39276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int mWritingDirection; 39376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String mRegionId; 39476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean mSnapToLines; 39576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Integer mLinePosition; // null means AUTO 39676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean mAutoLinePosition; 39776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int mTextPosition; 39876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int mSize; 39976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int mAlignment; 40076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // Vector<String> mText; 40176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String[] mStrings; 40276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCueSpan[][] mLines; 40376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackRegion mRegion; 40476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 40576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCue() { 40676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mId = ""; 40776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPauseOnExit = false; 40876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mWritingDirection = WRITING_DIRECTION_HORIZONTAL; 40976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mRegionId = ""; 41076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mSnapToLines = true; 41176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLinePosition = null /* AUTO */; 41276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTextPosition = 50; 41376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mSize = 100; 41476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAlignment = ALIGNMENT_MIDDLE; 41576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLines = null; 41676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mRegion = null; 41776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 41876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 41976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 42076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public boolean equals(Object o) { 42176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!(o instanceof TextTrackCue)) { 42276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return false; 42376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 42476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (this == o) { 42576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return true; 42676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 42776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 42876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 42976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCue cue = (TextTrackCue) o; 43076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean res = mId.equals(cue.mId) && 43176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPauseOnExit == cue.mPauseOnExit && 43276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mWritingDirection == cue.mWritingDirection && 43376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mRegionId.equals(cue.mRegionId) && 43476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mSnapToLines == cue.mSnapToLines && 43576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAutoLinePosition == cue.mAutoLinePosition && 4365c5978985a3457539d1f3b611f23d26b77484536Andreas Gampe (mAutoLinePosition || 4375c5978985a3457539d1f3b611f23d26b77484536Andreas Gampe ((mLinePosition != null && mLinePosition.equals(cue.mLinePosition)) || 4385c5978985a3457539d1f3b611f23d26b77484536Andreas Gampe (mLinePosition == null && cue.mLinePosition == null))) && 43976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTextPosition == cue.mTextPosition && 44076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mSize == cue.mSize && 44176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAlignment == cue.mAlignment && 44276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLines.length == cue.mLines.length; 44376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (res == true) { 44476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (int line = 0; line < mLines.length; line++) { 44576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!Arrays.equals(mLines[line], cue.mLines[line])) { 44676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return false; 44776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 44876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 44976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 45076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return res; 45176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch(IncompatibleClassChangeError e) { 45276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return false; 45376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 45476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 45576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 45676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public StringBuilder appendStringsToBuilder(StringBuilder builder) { 45776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mStrings == null) { 45876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("null"); 45976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 46076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("["); 46176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean first = true; 46276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (String s: mStrings) { 46376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!first) { 46476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append(", "); 46576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 46676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (s == null) { 46776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("null"); 46876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 46976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("\""); 47076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append(s); 47176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("\""); 47276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 47376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar first = false; 47476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 47576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("]"); 47676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 47776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return builder; 47876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 47976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 48076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public StringBuilder appendLinesToBuilder(StringBuilder builder) { 48176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mLines == null) { 48276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("null"); 48376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 48476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("["); 48576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean first = true; 48676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (TextTrackCueSpan[] spans: mLines) { 48776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!first) { 48876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append(", "); 48976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 49076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (spans == null) { 49176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("null"); 49276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 49376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("\""); 49476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean innerFirst = true; 49576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar long lastTimestamp = -1; 49676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (TextTrackCueSpan span: spans) { 49776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!innerFirst) { 49876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append(" "); 49976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 50076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (span.mTimestampMs != lastTimestamp) { 50176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("<") 50276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(WebVttParser.timeToString( 50376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar span.mTimestampMs)) 50476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(">"); 50576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar lastTimestamp = span.mTimestampMs; 50676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 50776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append(span.mText); 50876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar innerFirst = false; 50976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 51076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("\""); 51176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 51276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar first = false; 51376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 51476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("]"); 51576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 51676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return builder; 51776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 51876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 51976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public String toString() { 52076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar StringBuilder res = new StringBuilder(); 52176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 52276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar res.append(WebVttParser.timeToString(mStartTimeMs)) 52376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(" --> ").append(WebVttParser.timeToString(mEndTimeMs)) 52476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(" {id:\"").append(mId) 52576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append("\", pauseOnExit:").append(mPauseOnExit) 52676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", direction:") 52776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(mWritingDirection == WRITING_DIRECTION_HORIZONTAL ? "horizontal" : 52876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mWritingDirection == WRITING_DIRECTION_VERTICAL_LR ? "vertical_lr" : 52976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mWritingDirection == WRITING_DIRECTION_VERTICAL_RL ? "vertical_rl" : 53076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "INVALID") 53176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", regionId:\"").append(mRegionId) 53276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append("\", snapToLines:").append(mSnapToLines) 53376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", linePosition:").append(mAutoLinePosition ? "auto" : 53476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLinePosition) 53576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", textPosition:").append(mTextPosition) 53676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", size:").append(mSize) 53776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", alignment:") 53876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(mAlignment == ALIGNMENT_END ? "end" : 53976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAlignment == ALIGNMENT_LEFT ? "left" : 54076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAlignment == ALIGNMENT_MIDDLE ? "middle" : 54176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAlignment == ALIGNMENT_RIGHT ? "right" : 54276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAlignment == ALIGNMENT_START ? "start" : "INVALID") 54376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", text:"); 54476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar appendStringsToBuilder(res).append("}"); 54576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return res.toString(); 54676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 54776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 54876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 54976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public int hashCode() { 55076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return toString().hashCode(); 55176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 55276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 55376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 55476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void onTime(long timeMs) { 55576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (TextTrackCueSpan[] line: mLines) { 55676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (TextTrackCueSpan span: line) { 55776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar span.mEnabled = timeMs >= span.mTimestampMs; 55876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 55976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 56076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 56176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 56276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 56372bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar/** 56472bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar * Supporting July 10 2013 draft version 56572bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar * 56672bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar * @hide 56772bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar */ 56876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarclass WebVttParser { 56976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private static final String TAG = "WebVttParser"; 57076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private Phase mPhase; 57176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private TextTrackCue mCue; 57276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private Vector<String> mCueTexts; 57376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private WebVttCueListener mListener; 57476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private String mBuffer; 57576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 57676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar WebVttParser(WebVttCueListener listener) { 57776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseStart; 57876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer = ""; /* mBuffer contains up to 1 incomplete line */ 57976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mListener = listener; 58076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCueTexts = new Vector<String>(); 58176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 58276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 58376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar /* parsePercentageString */ 58476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public static float parseFloatPercentage(String s) 58576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throws NumberFormatException { 58676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!s.endsWith("%")) { 58776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("does not end in %"); 58876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 58976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar s = s.substring(0, s.length() - 1); 59076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // parseFloat allows an exponent or a sign 59176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (s.matches(".*[^0-9.].*")) { 59276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("contains an invalid character"); 59376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 59476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 59576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 59676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar float value = Float.parseFloat(s); 59776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (value < 0.0f || value > 100.0f) { 59876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("is out of range"); 59976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 60076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return value; 60176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 60276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("is not a number"); 60376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 60476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 60576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 60676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public static int parseIntPercentage(String s) throws NumberFormatException { 60776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!s.endsWith("%")) { 60876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("does not end in %"); 60976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 61076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar s = s.substring(0, s.length() - 1); 61176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // parseInt allows "-0" that returns 0, so check for non-digits 61276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (s.matches(".*[^0-9].*")) { 61376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("contains an invalid character"); 61476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 61576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 61676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 61776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int value = Integer.parseInt(s); 61876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (value < 0 || value > 100) { 61976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("is out of range"); 62076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 62176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return value; 62276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 62376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("is not a number"); 62476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 62576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 62676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 62776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public static long parseTimestampMs(String s) throws NumberFormatException { 62876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!s.matches("(\\d+:)?[0-5]\\d:[0-5]\\d\\.\\d{3}")) { 62976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("has invalid format"); 63076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 63176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 63276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String[] parts = s.split("\\.", 2); 63376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar long value = 0; 63476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (String group: parts[0].split(":")) { 63576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar value = value * 60 + Long.parseLong(group); 63676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 63776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return value * 1000 + Long.parseLong(parts[1]); 63876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 63976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 64076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public static String timeToString(long timeMs) { 64176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return String.format("%d:%02d:%02d.%03d", 64276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar timeMs / 3600000, (timeMs / 60000) % 60, 64376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar (timeMs / 1000) % 60, timeMs % 1000); 64476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 64576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 64676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String s) { 64776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean trailingCR = false; 64876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer = (mBuffer + s.replace("\0", "\ufffd")).replace("\r\n", "\n"); 64976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 65076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar /* keep trailing '\r' in case matching '\n' arrives in next packet */ 65176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mBuffer.endsWith("\r")) { 65276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar trailingCR = true; 65376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer = mBuffer.substring(0, mBuffer.length() - 1); 65476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 65576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 65676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String[] lines = mBuffer.split("[\r\n]"); 65776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (int i = 0; i < lines.length - 1; i++) { 65876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase.parse(lines[i]); 65976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 66076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 66176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer = lines[lines.length - 1]; 66276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (trailingCR) 66376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer += "\r"; 66476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 66576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 66676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void eos() { 66776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mBuffer.endsWith("\r")) { 66876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer = mBuffer.substring(0, mBuffer.length() - 1); 66976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 67076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 67176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase.parse(mBuffer); 67276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer = ""; 67376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 67476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar yieldCue(); 67576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseStart; 67676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 67776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 67876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void yieldCue() { 67976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mCue != null && mCueTexts.size() > 0) { 68076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mStrings = new String[mCueTexts.size()]; 68176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCueTexts.toArray(mCue.mStrings); 68276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCueTexts.clear(); 68376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mListener.onCueParsed(mCue); 68476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 68576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue = null; 68676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 68776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 68876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar interface Phase { 68976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void parse(String line); 69076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 69176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 69276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final private Phase mSkipRest = new Phase() { 69376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 69476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String line) { } 69576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar }; 69676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 69776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final private Phase mParseStart = new Phase() { // 5-9 69876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 69976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String line) { 700283fe37aa20d6f5910ed1c86847c6228e151e1ffLajos Molnar if (line.startsWith("\ufeff")) { 701283fe37aa20d6f5910ed1c86847c6228e151e1ffLajos Molnar line = line.substring(1); 702283fe37aa20d6f5910ed1c86847c6228e151e1ffLajos Molnar } 70376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!line.equals("WEBVTT") && 70476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar !line.startsWith("WEBVTT ") && 70576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar !line.startsWith("WEBVTT\t")) { 70676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("Not a WEBVTT header", line); 70776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mSkipRest; 70876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 70976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseHeader; 71076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 71176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 71276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar }; 71376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 71476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final private Phase mParseHeader = new Phase() { // 10-13 71576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackRegion parseRegion(String s) { 71676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackRegion region = new TextTrackRegion(); 71776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (String setting: s.split(" +")) { 71876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int equalAt = setting.indexOf('='); 71976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (equalAt <= 0 || equalAt == setting.length() - 1) { 72076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 72176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 72276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 72376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String name = setting.substring(0, equalAt); 72476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String value = setting.substring(equalAt + 1); 72576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (name.equals("id")) { 72676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mId = value; 72776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("width")) { 72876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 72976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mWidth = parseFloatPercentage(value); 73076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 73176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("region setting", name, 73276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "has invalid value", e.getMessage(), value); 73376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 73476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("lines")) { 73572bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar if (value.matches(".*[^0-9].*")) { 73672bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar log_warning("lines", name, "contains an invalid character", value); 73772bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar } else { 73872bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar try { 73972bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar region.mLines = Integer.parseInt(value); 74072bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar assert(region.mLines >= 0); // lines contains only digits 74172bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar } catch (NumberFormatException e) { 74272bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar log_warning("region setting", name, "is not numeric", value); 74376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 74476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 74576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("regionanchor") || 74676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar name.equals("viewportanchor")) { 74776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int commaAt = value.indexOf(","); 74876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (commaAt < 0) { 74976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("region setting", name, "contains no comma", value); 75076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 75176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 75276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 75376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String anchorX = value.substring(0, commaAt); 75476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String anchorY = value.substring(commaAt + 1); 75576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar float x, y; 75676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 75776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 75876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar x = parseFloatPercentage(anchorX); 75976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 76076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("region setting", name, 76176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "has invalid x component", e.getMessage(), anchorX); 76276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 76376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 76476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 76576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar y = parseFloatPercentage(anchorY); 76676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 76776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("region setting", name, 76876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "has invalid y component", e.getMessage(), anchorY); 76976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 77076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 77176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 77276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (name.charAt(0) == 'r') { 77376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mAnchorPointX = x; 77476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mAnchorPointY = y; 77576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 77676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mViewportAnchorPointX = x; 77776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mViewportAnchorPointY = y; 77876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 77976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("scroll")) { 78076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (value.equals("up")) { 78176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mScrollValue = 78276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackRegion.SCROLL_VALUE_SCROLL_UP; 78376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 78476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("region setting", name, "has invalid value", value); 78576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 78676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 78776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 78876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return region; 78976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 79076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 79176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 79276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String line) { 79376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (line.length() == 0) { 79476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueId; 79576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (line.contains("-->")) { 79676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueTime; 79776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase.parse(line); 79876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 79976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int colonAt = line.indexOf(':'); 80076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (colonAt <= 0 || colonAt >= line.length() - 1) { 80176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("meta data header has invalid format", line); 80276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 80376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String name = line.substring(0, colonAt); 80476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String value = line.substring(colonAt + 1); 80576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 80676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (name.equals("Region")) { 80776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackRegion region = parseRegion(value); 80876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mListener.onRegionParsed(region); 80976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 81076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 81176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 81276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar }; 81376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 81476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final private Phase mParseCueId = new Phase() { 81576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 81676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String line) { 81776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (line.length() == 0) { 81876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return; 81976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 82076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 82176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar assert(mCue == null); 82276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 82376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (line.equals("NOTE") || line.startsWith("NOTE ")) { 82476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueText; 82576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 82676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 82776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue = new TextTrackCue(); 82876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCueTexts.clear(); 82976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 83076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueTime; 83176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (line.contains("-->")) { 83276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase.parse(line); 83376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 83476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mId = line; 83576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 83676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 83776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar }; 83876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 83976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final private Phase mParseCueTime = new Phase() { 84076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 84176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String line) { 84276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int arrowAt = line.indexOf("-->"); 84376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (arrowAt < 0) { 84476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue = null; 84576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueId; 84676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return; 84776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 84876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 84976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String start = line.substring(0, arrowAt).trim(); 85076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // convert only initial and first other white-space to space 85176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String rest = line.substring(arrowAt + 3) 85276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .replaceFirst("^\\s+", "").replaceFirst("\\s+", " "); 85376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int spaceAt = rest.indexOf(' '); 85476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String end = spaceAt > 0 ? rest.substring(0, spaceAt) : rest; 85576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar rest = spaceAt > 0 ? rest.substring(spaceAt + 1) : ""; 85676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 85776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mStartTimeMs = parseTimestampMs(start); 85876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mEndTimeMs = parseTimestampMs(end); 85976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (String setting: rest.split(" +")) { 86076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int colonAt = setting.indexOf(':'); 86176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (colonAt <= 0 || colonAt == setting.length() - 1) { 86276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 86376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 86476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String name = setting.substring(0, colonAt); 86576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String value = setting.substring(colonAt + 1); 86676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 86776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (name.equals("region")) { 86876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mRegionId = value; 86976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("vertical")) { 87076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (value.equals("rl")) { 87176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mWritingDirection = 87276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCue.WRITING_DIRECTION_VERTICAL_RL; 87376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (value.equals("lr")) { 87476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mWritingDirection = 87576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCue.WRITING_DIRECTION_VERTICAL_LR; 87676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 87776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("cue setting", name, "has invalid value", value); 87876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 87976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("line")) { 88076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 88176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar /* TRICKY: we know that there are no spaces in value */ 88276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar assert(value.indexOf(' ') < 0); 88376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (value.endsWith("%")) { 88476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mSnapToLines = false; 88572bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar mCue.mLinePosition = parseIntPercentage(value); 88672bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar } else if (value.matches(".*[^0-9].*")) { 88772bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar log_warning("cue setting", name, 88872bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar "contains an invalid character", value); 88976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 89076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mSnapToLines = true; 89176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mLinePosition = Integer.parseInt(value); 89276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 89376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 89476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("cue setting", name, 89572bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar "is not numeric or percentage", value); 89676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 89772bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar // TODO: add support for optional alignment value [,start|middle|end] 89876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("position")) { 89976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 90076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mTextPosition = parseIntPercentage(value); 90176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 90276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("cue setting", name, 90376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "is not numeric or percentage", value); 90476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 90576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("size")) { 90676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 90776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mSize = parseIntPercentage(value); 90876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 90976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("cue setting", name, 91076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "is not numeric or percentage", value); 91176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 91276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("align")) { 91376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (value.equals("start")) { 91476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mAlignment = TextTrackCue.ALIGNMENT_START; 91576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (value.equals("middle")) { 91676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mAlignment = TextTrackCue.ALIGNMENT_MIDDLE; 91776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (value.equals("end")) { 91876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mAlignment = TextTrackCue.ALIGNMENT_END; 91976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (value.equals("left")) { 92076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mAlignment = TextTrackCue.ALIGNMENT_LEFT; 92176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (value.equals("right")) { 92276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mAlignment = TextTrackCue.ALIGNMENT_RIGHT; 92376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 92476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("cue setting", name, "has invalid value", value); 92576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 92676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 92776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 92876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 92976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 93076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mCue.mLinePosition != null || 93176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mSize != 100 || 93276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar (mCue.mWritingDirection != 93376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCue.WRITING_DIRECTION_HORIZONTAL)) { 93476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mRegionId = ""; 93576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 93676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 93776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueText; 93876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 93976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar }; 94076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 94176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar /* also used for notes */ 94276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final private Phase mParseCueText = new Phase() { 94376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 94476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String line) { 94576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (line.length() == 0) { 94676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar yieldCue(); 94776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueId; 94876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return; 94976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (mCue != null) { 95076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCueTexts.add(line); 95176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 95276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 95376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar }; 95476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 95576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private void log_warning( 95676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String nameType, String name, String message, 95776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String subMessage, String value) { 95876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Log.w(this.getClass().getName(), nameType + " '" + name + "' " + 95976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar message + " ('" + value + "' " + subMessage + ")"); 96076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 96176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 96276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private void log_warning( 96376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String nameType, String name, String message, String value) { 96476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Log.w(this.getClass().getName(), nameType + " '" + name + "' " + 96576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar message + " ('" + value + "')"); 96676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 96776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 96876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private void log_warning(String message, String value) { 96976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Log.w(this.getClass().getName(), message + " ('" + value + "')"); 97076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 97176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 97276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 97376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar/** @hide */ 97476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarinterface WebVttCueListener { 97576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void onCueParsed(TextTrackCue cue); 97676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void onRegionParsed(TextTrackRegion region); 97776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 97876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 97976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar/** @hide */ 98076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarclass WebVttTrack extends SubtitleTrack implements WebVttCueListener { 98176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private static final String TAG = "WebVttTrack"; 98276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 98376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private final WebVttParser mParser = new WebVttParser(this); 98476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private final UnstyledTextExtractor mExtractor = 98576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar new UnstyledTextExtractor(); 98676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private final Tokenizer mTokenizer = new Tokenizer(mExtractor); 98776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private final Vector<Long> mTimestamps = new Vector<Long>(); 988d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final WebVttRenderingWidget mRenderingWidget; 98976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 99076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private final Map<String, TextTrackRegion> mRegions = 99176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar new HashMap<String, TextTrackRegion>(); 99276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private Long mCurrentRunID; 99376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 994d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette WebVttTrack(WebVttRenderingWidget renderingWidget, MediaFormat format) { 99576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar super(format); 996d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 997d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mRenderingWidget = renderingWidget; 99876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 99976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 100076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 1001d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public WebVttRenderingWidget getRenderingWidget() { 1002d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return mRenderingWidget; 100376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 100476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 100576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 1006079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang public void onData(byte[] data, boolean eos, long runID) { 1007079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang try { 1008079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang String str = new String(data, "UTF-8"); 1009079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang 1010079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang // implement intermixing restriction for WebVTT only for now 1011079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang synchronized(mParser) { 1012079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang if (mCurrentRunID != null && runID != mCurrentRunID) { 1013079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang throw new IllegalStateException( 1014079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang "Run #" + mCurrentRunID + 1015079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang " in progress. Cannot process run #" + runID); 1016079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang } 1017079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang mCurrentRunID = runID; 1018079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang mParser.parse(str); 1019079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang if (eos) { 1020079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang finishedRun(runID); 1021079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang mParser.eos(); 1022079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang mRegions.clear(); 1023079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang mCurrentRunID = null; 1024079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang } 102576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 1026079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang } catch (java.io.UnsupportedEncodingException e) { 1027079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e); 102876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 102976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 103076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 103176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 103276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void onCueParsed(TextTrackCue cue) { 103376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar synchronized (mParser) { 103476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // resolve region 103576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (cue.mRegionId.length() != 0) { 103676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.mRegion = mRegions.get(cue.mRegionId); 103776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 103876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 103976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (DEBUG) Log.v(TAG, "adding cue " + cue); 104076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 104176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // tokenize text track string-lines into lines of spans 104276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTokenizer.reset(); 104376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (String s: cue.mStrings) { 104476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTokenizer.tokenize(s); 104576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 104676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.mLines = mExtractor.getText(); 104776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (DEBUG) Log.v(TAG, cue.appendLinesToBuilder( 104876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.appendStringsToBuilder( 104976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar new StringBuilder()).append(" simplified to: ")) 105076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .toString()); 105176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 105276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // extract inner timestamps 105376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (TextTrackCueSpan[] line: cue.mLines) { 105476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (TextTrackCueSpan span: line) { 105576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (span.mTimestampMs > cue.mStartTimeMs && 105676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar span.mTimestampMs < cue.mEndTimeMs && 105776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar !mTimestamps.contains(span.mTimestampMs)) { 105876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTimestamps.add(span.mTimestampMs); 105976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 106076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 106176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 106276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 106376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mTimestamps.size() > 0) { 106476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.mInnerTimesMs = new long[mTimestamps.size()]; 106576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (int ix=0; ix < mTimestamps.size(); ++ix) { 106676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.mInnerTimesMs[ix] = mTimestamps.get(ix); 106776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 106876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTimestamps.clear(); 106976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 107076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.mInnerTimesMs = null; 107176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 107276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 107376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.mRunID = mCurrentRunID; 107476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 107576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 107676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar addCue(cue); 107776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 107876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 107976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 108076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void onRegionParsed(TextTrackRegion region) { 108176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar synchronized(mParser) { 108276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mRegions.put(region.mId, region); 108376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 108476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 108576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 1086d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 108776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void updateView(Vector<SubtitleTrack.Cue> activeCues) { 108876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!mVisible) { 108976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // don't keep the state if we are not visible 109076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return; 109176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 109276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 109376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (DEBUG && mTimeProvider != null) { 109476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 109576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Log.d(TAG, "at " + 109676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar (mTimeProvider.getCurrentTimeUs(false, true) / 1000) + 109776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar " ms the active cues are:"); 109876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (IllegalStateException e) { 109976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Log.d(TAG, "at (illegal state) the active cues are:"); 110076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 110176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 1102d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 11033cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih if (mRenderingWidget != null) { 11043cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih mRenderingWidget.setActiveCues(activeCues); 11053cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1106d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1107d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette} 1108d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1109d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette/** 1110d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Widget capable of rendering WebVTT captions. 1111d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 1112d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @hide 1113d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1114d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteclass WebVttRenderingWidget extends ViewGroup implements SubtitleTrack.RenderingWidget { 1115d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static final boolean DEBUG = false; 1116e88aee8ad85b01229b12dbc0c3cc2f0b8b490192Alan Viverette 1117e88aee8ad85b01229b12dbc0c3cc2f0b8b490192Alan Viverette private static final CaptionStyle DEFAULT_CAPTION_STYLE = CaptionStyle.DEFAULT; 1118e88aee8ad85b01229b12dbc0c3cc2f0b8b490192Alan Viverette 1119d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static final int DEBUG_REGION_BACKGROUND = 0x800000FF; 1120d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static final int DEBUG_CUE_BACKGROUND = 0x80FF0000; 1121d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1122d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** WebVtt specifies line height as 5.3% of the viewport height. */ 1123d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static final float LINE_HEIGHT_RATIO = 0.0533f; 1124d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1125d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Map of active regions, used to determine enter/exit. */ 1126d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final ArrayMap<TextTrackRegion, RegionLayout> mRegionBoxes = 1127d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette new ArrayMap<TextTrackRegion, RegionLayout>(); 1128d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1129d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Map of active cues, used to determine enter/exit. */ 1130d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final ArrayMap<TextTrackCue, CueLayout> mCueBoxes = 1131d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette new ArrayMap<TextTrackCue, CueLayout>(); 1132d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1133d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Captioning manager, used to obtain and track caption properties. */ 1134d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final CaptioningManager mManager; 1135d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1136d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Callback for rendering changes. */ 1137d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private OnChangedListener mListener; 1138d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1139d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Current caption style. */ 1140d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private CaptionStyle mCaptionStyle; 1141d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1142d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Current font size, computed from font scaling factor and height. */ 1143d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private float mFontSize; 1144d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1145d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Whether a caption style change listener is registered. */ 1146d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private boolean mHasChangeListener; 1147d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1148d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public WebVttRenderingWidget(Context context) { 1149d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette this(context, null); 1150d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1151d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1152d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public WebVttRenderingWidget(Context context, AttributeSet attrs) { 1153d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette this(context, attrs, 0); 1154d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1155d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1156617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public WebVttRenderingWidget(Context context, AttributeSet attrs, int defStyleAttr) { 1157617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette this(context, attrs, defStyleAttr, 0); 1158617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette } 1159617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette 1160e88aee8ad85b01229b12dbc0c3cc2f0b8b490192Alan Viverette public WebVttRenderingWidget( 1161e88aee8ad85b01229b12dbc0c3cc2f0b8b490192Alan Viverette Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 1162617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette super(context, attrs, defStyleAttr, defStyleRes); 1163d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1164d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Cannot render text over video when layer type is hardware. 1165d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setLayerType(View.LAYER_TYPE_SOFTWARE, null); 1166d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1167d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mManager = (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE); 1168d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCaptionStyle = mManager.getUserStyle(); 1169d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mFontSize = mManager.getFontScale() * getHeight() * LINE_HEIGHT_RATIO; 1170d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1171d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1172d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1173d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setSize(int width, int height) { 1174d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); 1175d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); 1176d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1177d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette measure(widthSpec, heightSpec); 1178d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette layout(0, 0, width, height); 1179d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1180d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1181d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1182d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onAttachedToWindow() { 1183d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onAttachedToWindow(); 1184d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1185d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette manageChangeListener(); 1186d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1187d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1188d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1189d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onDetachedFromWindow() { 1190d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onDetachedFromWindow(); 1191d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1192d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette manageChangeListener(); 1193d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1194d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1195d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1196d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setOnChangedListener(OnChangedListener listener) { 1197d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mListener = listener; 1198d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1199d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1200d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1201d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setVisible(boolean visible) { 1202d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (visible) { 1203d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setVisibility(View.VISIBLE); 1204d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 1205d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setVisibility(View.GONE); 1206d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1207d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1208d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette manageChangeListener(); 1209d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1210d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1211d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1212d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Manages whether this renderer is listening for caption style changes. 1213d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1214d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void manageChangeListener() { 1215d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final boolean needsListener = isAttachedToWindow() && getVisibility() == View.VISIBLE; 1216d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mHasChangeListener != needsListener) { 1217d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mHasChangeListener = needsListener; 1218d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1219d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (needsListener) { 1220d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mManager.addCaptioningChangeListener(mCaptioningListener); 1221d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1222d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CaptionStyle captionStyle = mManager.getUserStyle(); 1223d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float fontSize = mManager.getFontScale() * getHeight() * LINE_HEIGHT_RATIO; 1224d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setCaptionStyle(captionStyle, fontSize); 1225d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 1226d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mManager.removeCaptioningChangeListener(mCaptioningListener); 1227d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1228d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1229d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1230d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1231d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setActiveCues(Vector<SubtitleTrack.Cue> activeCues) { 1232d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final Context context = getContext(); 1233d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CaptionStyle captionStyle = mCaptionStyle; 1234d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float fontSize = mFontSize; 1235d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1236d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette prepForPrune(); 1237d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1238d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Ensure we have all necessary cue and region boxes. 1239d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int count = activeCues.size(); 1240d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < count; i++) { 1241d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCue cue = (TextTrackCue) activeCues.get(i); 1242d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackRegion region = cue.mRegion; 1243d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (region != null) { 1244d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette RegionLayout regionBox = mRegionBoxes.get(region); 1245d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (regionBox == null) { 1246d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionBox = new RegionLayout(context, region, captionStyle, fontSize); 1247d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mRegionBoxes.put(region, regionBox); 1248d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette addView(regionBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 124976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 1250d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionBox.put(cue); 1251d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 1252d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette CueLayout cueBox = mCueBoxes.get(cue); 1253d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (cueBox == null) { 1254d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox = new CueLayout(context, cue, captionStyle, fontSize); 1255d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCueBoxes.put(cue, cueBox); 1256d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette addView(cueBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 125776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 1258d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.update(); 1259d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.setOrder(i); 1260d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1261d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1262d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1263d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette prune(); 1264d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1265d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Force measurement and layout. 1266d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int width = getWidth(); 1267d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int height = getHeight(); 1268d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setSize(width, height); 1269d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1270d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mListener != null) { 1271d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mListener.onChanged(this); 1272d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1273d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1274d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1275d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void setCaptionStyle(CaptionStyle captionStyle, float fontSize) { 1276e88aee8ad85b01229b12dbc0c3cc2f0b8b490192Alan Viverette captionStyle = DEFAULT_CAPTION_STYLE.applyStyle(captionStyle); 1277d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCaptionStyle = captionStyle; 1278d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mFontSize = fontSize; 1279d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1280d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mCueBoxes.size(); 1281d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1282d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mCueBoxes.valueAt(i); 1283d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.setCaptionStyle(captionStyle, fontSize); 1284d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1285d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1286d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int regionCount = mRegionBoxes.size(); 1287d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < regionCount; i++) { 1288d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final RegionLayout regionBox = mRegionBoxes.valueAt(i); 1289d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionBox.setCaptionStyle(captionStyle, fontSize); 1290d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1291d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1292d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1293d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1294d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Remove inactive cues and regions. 1295d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1296d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void prune() { 1297d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int regionCount = mRegionBoxes.size(); 1298d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < regionCount; i++) { 1299d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final RegionLayout regionBox = mRegionBoxes.valueAt(i); 1300d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (regionBox.prune()) { 1301d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette removeView(regionBox); 1302d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mRegionBoxes.removeAt(i); 1303d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionCount--; 1304d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette i--; 130576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 130676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 130776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 1308d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int cueCount = mCueBoxes.size(); 1309d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1310d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mCueBoxes.valueAt(i); 1311d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (!cueBox.isActive()) { 1312d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette removeView(cueBox); 1313d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCueBoxes.removeAt(i); 1314d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueCount--; 1315d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette i--; 1316d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1317d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1318d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1319d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1320d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1321d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Reset active cues and regions. 1322d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1323d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void prepForPrune() { 1324d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int regionCount = mRegionBoxes.size(); 1325d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < regionCount; i++) { 1326d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final RegionLayout regionBox = mRegionBoxes.valueAt(i); 1327d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionBox.prepForPrune(); 1328d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1329d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1330d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mCueBoxes.size(); 1331d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1332d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mCueBoxes.valueAt(i); 1333d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.prepForPrune(); 1334d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1335d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1336d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1337d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1338d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1339d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onMeasure(widthMeasureSpec, heightMeasureSpec); 1340d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1341d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int regionCount = mRegionBoxes.size(); 1342d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < regionCount; i++) { 1343d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final RegionLayout regionBox = mRegionBoxes.valueAt(i); 1344d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionBox.measureForParent(widthMeasureSpec, heightMeasureSpec); 1345d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1346d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1347d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mCueBoxes.size(); 1348d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1349d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mCueBoxes.valueAt(i); 1350d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.measureForParent(widthMeasureSpec, heightMeasureSpec); 1351d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1352d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1353d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1354d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1355d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette protected void onLayout(boolean changed, int l, int t, int r, int b) { 1356d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int viewportWidth = r - l; 1357d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int viewportHeight = b - t; 1358d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1359d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setCaptionStyle(mCaptionStyle, 1360d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mManager.getFontScale() * LINE_HEIGHT_RATIO * viewportHeight); 1361d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1362d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int regionCount = mRegionBoxes.size(); 1363d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < regionCount; i++) { 1364d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final RegionLayout regionBox = mRegionBoxes.valueAt(i); 1365d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette layoutRegion(viewportWidth, viewportHeight, regionBox); 1366d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1367d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1368d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mCueBoxes.size(); 1369d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1370d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mCueBoxes.valueAt(i); 1371d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette layoutCue(viewportWidth, viewportHeight, cueBox); 1372d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1373d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1374d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1375d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1376d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Lays out a region within the viewport. The region handles layout for 1377d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * contained cues. 1378d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1379d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void layoutRegion( 1380d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int viewportWidth, int viewportHeight, 1381d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette RegionLayout regionBox) { 1382d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackRegion region = regionBox.getRegion(); 1383d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int regionHeight = regionBox.getMeasuredHeight(); 1384d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int regionWidth = regionBox.getMeasuredWidth(); 1385d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1386d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // TODO: Account for region anchor point. 1387d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float x = region.mViewportAnchorPointX; 1388d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float y = region.mViewportAnchorPointY; 1389d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int left = (int) (x * (viewportWidth - regionWidth) / 100); 1390d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int top = (int) (y * (viewportHeight - regionHeight) / 100); 1391d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1392d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionBox.layout(left, top, left + regionWidth, top + regionHeight); 1393d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1394d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1395d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1396d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Lays out a cue within the viewport. 1397d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1398d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void layoutCue( 1399d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int viewportWidth, int viewportHeight, CueLayout cueBox) { 1400d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCue cue = cueBox.getCue(); 1401d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int direction = getLayoutDirection(); 1402d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int absAlignment = resolveCueAlignment(direction, cue.mAlignment); 1403d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final boolean cueSnapToLines = cue.mSnapToLines; 1404d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1405d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int size = 100 * cueBox.getMeasuredWidth() / viewportWidth; 1406d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1407d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Determine raw x-position. 1408d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int xPosition; 1409d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette switch (absAlignment) { 1410d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_LEFT: 1411d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette xPosition = cue.mTextPosition; 1412d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1413d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_RIGHT: 1414d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette xPosition = cue.mTextPosition - size; 1415d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1416d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_MIDDLE: 1417d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette default: 1418d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette xPosition = cue.mTextPosition - size / 2; 1419d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1420d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1421d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1422d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Adjust x-position for layout. 1423d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (direction == LAYOUT_DIRECTION_RTL) { 1424d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette xPosition = 100 - xPosition; 1425d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1426d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1427d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // If the text track cue snap-to-lines flag is set, adjust 1428d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // x-position and size for padding. This is equivalent to placing the 1429d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // cue within the title-safe area. 1430d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (cueSnapToLines) { 1431d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int paddingLeft = 100 * getPaddingLeft() / viewportWidth; 1432d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int paddingRight = 100 * getPaddingRight() / viewportWidth; 1433d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (xPosition < paddingLeft && xPosition + size > paddingLeft) { 1434d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette xPosition += paddingLeft; 1435d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette size -= paddingLeft; 1436d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1437d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float rightEdge = 100 - paddingRight; 1438d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (xPosition < rightEdge && xPosition + size > rightEdge) { 1439d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette size -= paddingRight; 1440d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1441d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1442d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1443d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Compute absolute left position and width. 1444d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int left = xPosition * viewportWidth / 100; 1445d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int width = size * viewportWidth / 100; 1446d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1447d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Determine initial y-position. 1448d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int yPosition = calculateLinePosition(cueBox); 1449d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1450d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Compute absolute final top position and height. 1451d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int height = cueBox.getMeasuredHeight(); 1452d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int top; 1453d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (yPosition < 0) { 1454d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // TODO: This needs to use the actual height of prior boxes. 1455d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette top = viewportHeight + yPosition * height; 1456d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 1457d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette top = yPosition * (viewportHeight - height) / 100; 1458d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1459d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1460d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Layout cue in final position. 1461d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.layout(left, top, left + width, top + height); 1462d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1463d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1464d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1465d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Calculates the line position for a cue. 1466d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * <p> 1467d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * If the resulting position is negative, it represents a bottom-aligned 1468d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * position relative to the number of active cues. Otherwise, it represents 1469d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * a percentage [0-100] of the viewport height. 1470d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1471d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private int calculateLinePosition(CueLayout cueBox) { 1472d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCue cue = cueBox.getCue(); 1473d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final Integer linePosition = cue.mLinePosition; 1474d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final boolean snapToLines = cue.mSnapToLines; 1475d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final boolean autoPosition = (linePosition == null); 1476d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1477d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (!snapToLines && !autoPosition && (linePosition < 0 || linePosition > 100)) { 1478d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Invalid line position defaults to 100. 1479d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return 100; 1480d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else if (!autoPosition) { 1481d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Use the valid, supplied line position. 1482d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return linePosition; 1483d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else if (!snapToLines) { 1484d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Automatic, non-snapped line position defaults to 100. 1485d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return 100; 1486d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 1487d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Automatic snapped line position uses active cue order. 1488d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return -(cueBox.mOrder + 1); 1489d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1490d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1491d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1492d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1493d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Resolves cue alignment according to the specified layout direction. 1494d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1495d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static int resolveCueAlignment(int layoutDirection, int alignment) { 1496d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette switch (alignment) { 1497d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_START: 1498d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return layoutDirection == View.LAYOUT_DIRECTION_LTR ? 1499d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette TextTrackCue.ALIGNMENT_LEFT : TextTrackCue.ALIGNMENT_RIGHT; 1500d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_END: 1501d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return layoutDirection == View.LAYOUT_DIRECTION_LTR ? 1502d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette TextTrackCue.ALIGNMENT_RIGHT : TextTrackCue.ALIGNMENT_LEFT; 1503d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1504d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return alignment; 1505d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1506d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1507d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final CaptioningChangeListener mCaptioningListener = new CaptioningChangeListener() { 1508d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1509d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onFontScaleChanged(float fontScale) { 1510d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float fontSize = fontScale * getHeight() * LINE_HEIGHT_RATIO; 1511d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setCaptionStyle(mCaptionStyle, fontSize); 1512d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1513d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1514d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1515d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onUserStyleChanged(CaptionStyle userStyle) { 1516d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setCaptionStyle(userStyle, mFontSize); 1517d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1518d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette }; 1519d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1520d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1521d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * A text track region represents a portion of the video viewport and 1522d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * provides a rendering area for text track cues. 1523d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1524d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static class RegionLayout extends LinearLayout { 1525d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final ArrayList<CueLayout> mRegionCueBoxes = new ArrayList<CueLayout>(); 1526d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final TextTrackRegion mRegion; 1527d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1528d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private CaptionStyle mCaptionStyle; 1529d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private float mFontSize; 1530d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1531d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public RegionLayout(Context context, TextTrackRegion region, CaptionStyle captionStyle, 1532d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette float fontSize) { 1533d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super(context); 1534d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1535d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mRegion = region; 1536d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCaptionStyle = captionStyle; 1537d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mFontSize = fontSize; 1538d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1539d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // TODO: Add support for vertical text 1540d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setOrientation(VERTICAL); 1541d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1542d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (DEBUG) { 1543d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setBackgroundColor(DEBUG_REGION_BACKGROUND); 154455d70620d9fda8afafb2fdec59757a710eec0e89Alan Viverette } else { 154555d70620d9fda8afafb2fdec59757a710eec0e89Alan Viverette setBackgroundColor(captionStyle.windowColor); 1546d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1547d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1548d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1549d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setCaptionStyle(CaptionStyle captionStyle, float fontSize) { 1550d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCaptionStyle = captionStyle; 1551d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mFontSize = fontSize; 1552d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1553d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mRegionCueBoxes.size(); 1554d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1555d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mRegionCueBoxes.get(i); 1556d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.setCaptionStyle(captionStyle, fontSize); 1557d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 155855d70620d9fda8afafb2fdec59757a710eec0e89Alan Viverette 155955d70620d9fda8afafb2fdec59757a710eec0e89Alan Viverette setBackgroundColor(captionStyle.windowColor); 1560d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1561d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1562d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1563d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Performs the parent's measurement responsibilities, then 1564d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * automatically performs its own measurement. 1565d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1566d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void measureForParent(int widthMeasureSpec, int heightMeasureSpec) { 1567d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackRegion region = mRegion; 1568d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int specWidth = MeasureSpec.getSize(widthMeasureSpec); 1569d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int specHeight = MeasureSpec.getSize(heightMeasureSpec); 1570d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int width = (int) region.mWidth; 1571d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1572d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Determine the absolute maximum region size as the requested size. 1573d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int size = width * specWidth / 100; 1574d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1575d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette widthMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST); 1576d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette heightMeasureSpec = MeasureSpec.makeMeasureSpec(specHeight, MeasureSpec.AT_MOST); 1577d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette measure(widthMeasureSpec, heightMeasureSpec); 1578d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1579d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1580d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1581d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Prepares this region for pruning by setting all tracks as inactive. 1582d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * <p> 1583d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Tracks that are added or updated using {@link #put(TextTrackCue)} 1584d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * after this calling this method will be marked as active. 1585d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1586d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void prepForPrune() { 1587d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mRegionCueBoxes.size(); 1588d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1589d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mRegionCueBoxes.get(i); 1590d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.prepForPrune(); 1591d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1592d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1593d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1594d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1595d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Adds a {@link TextTrackCue} to this region. If the track had already 1596d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * been added, updates its active state. 1597d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 1598d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @param cue 1599d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1600d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void put(TextTrackCue cue) { 1601d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mRegionCueBoxes.size(); 1602d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1603d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mRegionCueBoxes.get(i); 1604d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (cueBox.getCue() == cue) { 1605d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.update(); 1606d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return; 1607d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1608d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1609d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1610d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = new CueLayout(getContext(), cue, mCaptionStyle, mFontSize); 16117fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette mRegionCueBoxes.add(cueBox); 1612d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette addView(cueBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 1613d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1614d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (getChildCount() > mRegion.mLines) { 1615d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette removeViewAt(0); 1616d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1617d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1618d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1619d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1620d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Remove all inactive tracks from this region. 1621d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 1622d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @return true if this region is empty and should be pruned 1623d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1624d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public boolean prune() { 1625d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int cueCount = mRegionCueBoxes.size(); 1626d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1627d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mRegionCueBoxes.get(i); 1628d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (!cueBox.isActive()) { 1629d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mRegionCueBoxes.remove(i); 1630d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette removeView(cueBox); 1631d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueCount--; 1632d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette i--; 1633d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1634d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1635d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1636d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return mRegionCueBoxes.isEmpty(); 1637d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1638d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1639d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1640d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @return the region data backing this layout 1641d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1642d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public TextTrackRegion getRegion() { 1643d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return mRegion; 1644d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1645d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1646d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1647d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1648d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * A text track cue is the unit of time-sensitive data in a text track, 1649d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * corresponding for instance for subtitles and captions to the text that 1650d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * appears at a particular time and disappears at another time. 1651d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * <p> 1652d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * A single cue may contain multiple {@link SpanLayout}s, each representing a 1653d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * single line of text. 1654d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1655d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static class CueLayout extends LinearLayout { 1656d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public final TextTrackCue mCue; 1657d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1658d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private CaptionStyle mCaptionStyle; 1659d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private float mFontSize; 1660d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1661d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private boolean mActive; 1662d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private int mOrder; 1663d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1664d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public CueLayout( 1665d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette Context context, TextTrackCue cue, CaptionStyle captionStyle, float fontSize) { 1666d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super(context); 1667d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1668d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCue = cue; 1669d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCaptionStyle = captionStyle; 1670d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mFontSize = fontSize; 1671d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1672d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // TODO: Add support for vertical text. 1673d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final boolean horizontal = cue.mWritingDirection 1674d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette == TextTrackCue.WRITING_DIRECTION_HORIZONTAL; 1675d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setOrientation(horizontal ? VERTICAL : HORIZONTAL); 1676d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1677d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette switch (cue.mAlignment) { 1678d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_END: 1679d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setGravity(Gravity.END); 1680d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1681d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_LEFT: 1682d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setGravity(Gravity.LEFT); 1683d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1684d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_MIDDLE: 1685d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setGravity(horizontal 1686d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette ? Gravity.CENTER_HORIZONTAL : Gravity.CENTER_VERTICAL); 1687d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1688d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_RIGHT: 1689d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setGravity(Gravity.RIGHT); 1690d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1691d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_START: 1692d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setGravity(Gravity.START); 1693d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1694d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1695d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1696d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (DEBUG) { 1697d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setBackgroundColor(DEBUG_CUE_BACKGROUND); 1698d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1699d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1700d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette update(); 1701d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1702d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1703d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setCaptionStyle(CaptionStyle style, float fontSize) { 1704d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCaptionStyle = style; 1705d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mFontSize = fontSize; 1706d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1707d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int n = getChildCount(); 1708d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < n; i++) { 1709d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final View child = getChildAt(i); 1710d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (child instanceof SpanLayout) { 1711d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette ((SpanLayout) child).setCaptionStyle(style, fontSize); 1712d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1713d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1714d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1715d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1716d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void prepForPrune() { 1717d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mActive = false; 1718d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1719d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1720d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void update() { 1721d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mActive = true; 1722d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1723d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette removeAllViews(); 1724d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 17257fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette final int cueAlignment = resolveCueAlignment(getLayoutDirection(), mCue.mAlignment); 17267fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette final Alignment alignment; 17277fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette switch (cueAlignment) { 17287fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette case TextTrackCue.ALIGNMENT_LEFT: 17297fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette alignment = Alignment.ALIGN_LEFT; 17307fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette break; 17317fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette case TextTrackCue.ALIGNMENT_RIGHT: 17327fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette alignment = Alignment.ALIGN_RIGHT; 17337fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette break; 17347fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette case TextTrackCue.ALIGNMENT_MIDDLE: 17357fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette default: 17367fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette alignment = Alignment.ALIGN_CENTER; 17377fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette } 17387fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette 1739d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CaptionStyle captionStyle = mCaptionStyle; 1740d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float fontSize = mFontSize; 1741d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCueSpan[][] lines = mCue.mLines; 1742d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int lineCount = lines.length; 1743d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < lineCount; i++) { 1744d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final SpanLayout lineBox = new SpanLayout(getContext(), lines[i]); 17457fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette lineBox.setAlignment(alignment); 1746d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette lineBox.setCaptionStyle(captionStyle, fontSize); 1747d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1748d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette addView(lineBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 1749d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1750d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1751d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1752d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1753d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1754d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onMeasure(widthMeasureSpec, heightMeasureSpec); 1755d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1756d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1757d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1758d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Performs the parent's measurement responsibilities, then 1759d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * automatically performs its own measurement. 1760d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1761d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void measureForParent(int widthMeasureSpec, int heightMeasureSpec) { 1762d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCue cue = mCue; 1763d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int specWidth = MeasureSpec.getSize(widthMeasureSpec); 1764d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int specHeight = MeasureSpec.getSize(heightMeasureSpec); 1765d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int direction = getLayoutDirection(); 1766d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int absAlignment = resolveCueAlignment(direction, cue.mAlignment); 1767d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1768d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Determine the maximum size of cue based on its starting position 1769d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // and the direction in which it grows. 1770d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int maximumSize; 1771d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette switch (absAlignment) { 1772d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_LEFT: 1773d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette maximumSize = 100 - cue.mTextPosition; 1774d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1775d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_RIGHT: 1776d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette maximumSize = cue.mTextPosition; 1777d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1778d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_MIDDLE: 1779d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (cue.mTextPosition <= 50) { 1780d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette maximumSize = cue.mTextPosition * 2; 1781d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 1782d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette maximumSize = (100 - cue.mTextPosition) * 2; 1783d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1784d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1785d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette default: 1786d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette maximumSize = 0; 1787d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1788d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1789d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Determine absolute maximum cue size as the smaller of the 1790d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // requested size and the maximum theoretical size. 1791d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int size = Math.min(cue.mSize, maximumSize) * specWidth / 100; 1792d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette widthMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST); 1793d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette heightMeasureSpec = MeasureSpec.makeMeasureSpec(specHeight, MeasureSpec.AT_MOST); 1794d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette measure(widthMeasureSpec, heightMeasureSpec); 1795d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1796d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1797d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1798d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Sets the order of this cue in the list of active cues. 1799d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 1800d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @param order the order of this cue in the list of active cues 1801d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1802d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setOrder(int order) { 1803d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mOrder = order; 1804d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1805d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1806d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1807d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @return whether this cue is marked as active 1808d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1809d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public boolean isActive() { 1810d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return mActive; 1811d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1812d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1813d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1814d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @return the cue data backing this layout 1815d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1816d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public TextTrackCue getCue() { 1817d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return mCue; 1818d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1819d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1820d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1821d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1822d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * A text track line represents a single line of text within a cue. 1823d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * <p> 1824d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * A single line may contain multiple spans, each representing a section of 1825d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * text that may be enabled or disabled at a particular time. 1826d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1827d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static class SpanLayout extends SubtitleView { 1828d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final SpannableStringBuilder mBuilder = new SpannableStringBuilder(); 1829d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final TextTrackCueSpan[] mSpans; 1830d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1831d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public SpanLayout(Context context, TextTrackCueSpan[] spans) { 1832d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super(context); 1833d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1834d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSpans = spans; 1835d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1836d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette update(); 1837d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1838d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1839d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void update() { 1840d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final SpannableStringBuilder builder = mBuilder; 1841d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCueSpan[] spans = mSpans; 1842d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1843d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette builder.clear(); 1844d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette builder.clearSpans(); 1845d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1846d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int spanCount = spans.length; 1847d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < spanCount; i++) { 1848d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCueSpan span = spans[i]; 1849d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (span.mEnabled) { 1850d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette builder.append(spans[i].mText); 1851d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1852d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1853d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1854d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setText(builder); 1855d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1856d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1857d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setCaptionStyle(CaptionStyle captionStyle, float fontSize) { 1858d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setBackgroundColor(captionStyle.backgroundColor); 1859d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setForegroundColor(captionStyle.foregroundColor); 1860d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setEdgeColor(captionStyle.edgeColor); 1861d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setEdgeType(captionStyle.edgeType); 1862d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setTypeface(captionStyle.getTypeface()); 1863d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setTextSize(fontSize); 186476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 186576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 186676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 1867