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 && 43676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar (mAutoLinePosition || mLinePosition == cue.mLinePosition) && 43776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTextPosition == cue.mTextPosition && 43876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mSize == cue.mSize && 43976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAlignment == cue.mAlignment && 44076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLines.length == cue.mLines.length; 44176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (res == true) { 44276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (int line = 0; line < mLines.length; line++) { 44376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!Arrays.equals(mLines[line], cue.mLines[line])) { 44476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return false; 44576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 44676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 44776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 44876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return res; 44976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch(IncompatibleClassChangeError e) { 45076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return false; 45176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 45276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 45376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 45476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public StringBuilder appendStringsToBuilder(StringBuilder builder) { 45576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mStrings == null) { 45676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("null"); 45776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 45876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("["); 45976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean first = true; 46076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (String s: mStrings) { 46176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!first) { 46276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append(", "); 46376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 46476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (s == null) { 46576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("null"); 46676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 46776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("\""); 46876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append(s); 46976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("\""); 47076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 47176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar first = false; 47276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 47376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("]"); 47476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 47576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return builder; 47676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 47776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 47876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public StringBuilder appendLinesToBuilder(StringBuilder builder) { 47976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mLines == null) { 48076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("null"); 48176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 48276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("["); 48376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean first = true; 48476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (TextTrackCueSpan[] spans: mLines) { 48576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!first) { 48676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append(", "); 48776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 48876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (spans == null) { 48976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("null"); 49076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 49176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("\""); 49276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean innerFirst = true; 49376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar long lastTimestamp = -1; 49476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (TextTrackCueSpan span: spans) { 49576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!innerFirst) { 49676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append(" "); 49776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 49876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (span.mTimestampMs != lastTimestamp) { 49976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("<") 50076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(WebVttParser.timeToString( 50176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar span.mTimestampMs)) 50276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(">"); 50376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar lastTimestamp = span.mTimestampMs; 50476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 50576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append(span.mText); 50676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar innerFirst = false; 50776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 50876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("\""); 50976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 51076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar first = false; 51176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 51276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar builder.append("]"); 51376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 51476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return builder; 51576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 51676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 51776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public String toString() { 51876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar StringBuilder res = new StringBuilder(); 51976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 52076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar res.append(WebVttParser.timeToString(mStartTimeMs)) 52176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(" --> ").append(WebVttParser.timeToString(mEndTimeMs)) 52276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(" {id:\"").append(mId) 52376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append("\", pauseOnExit:").append(mPauseOnExit) 52476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", direction:") 52576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(mWritingDirection == WRITING_DIRECTION_HORIZONTAL ? "horizontal" : 52676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mWritingDirection == WRITING_DIRECTION_VERTICAL_LR ? "vertical_lr" : 52776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mWritingDirection == WRITING_DIRECTION_VERTICAL_RL ? "vertical_rl" : 52876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "INVALID") 52976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", regionId:\"").append(mRegionId) 53076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append("\", snapToLines:").append(mSnapToLines) 53176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", linePosition:").append(mAutoLinePosition ? "auto" : 53276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mLinePosition) 53376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", textPosition:").append(mTextPosition) 53476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", size:").append(mSize) 53576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", alignment:") 53676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(mAlignment == ALIGNMENT_END ? "end" : 53776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAlignment == ALIGNMENT_LEFT ? "left" : 53876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAlignment == ALIGNMENT_MIDDLE ? "middle" : 53976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAlignment == ALIGNMENT_RIGHT ? "right" : 54076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mAlignment == ALIGNMENT_START ? "start" : "INVALID") 54176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .append(", text:"); 54276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar appendStringsToBuilder(res).append("}"); 54376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return res.toString(); 54476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 54576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 54676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 54776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public int hashCode() { 54876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return toString().hashCode(); 54976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 55076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 55176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 55276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void onTime(long timeMs) { 55376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (TextTrackCueSpan[] line: mLines) { 55476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (TextTrackCueSpan span: line) { 55576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar span.mEnabled = timeMs >= span.mTimestampMs; 55676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 55776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 55876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 55976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 56076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 56172bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar/** 56272bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar * Supporting July 10 2013 draft version 56372bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar * 56472bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar * @hide 56572bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar */ 56676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarclass WebVttParser { 56776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private static final String TAG = "WebVttParser"; 56876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private Phase mPhase; 56976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private TextTrackCue mCue; 57076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private Vector<String> mCueTexts; 57176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private WebVttCueListener mListener; 57276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private String mBuffer; 57376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 57476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar WebVttParser(WebVttCueListener listener) { 57576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseStart; 57676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer = ""; /* mBuffer contains up to 1 incomplete line */ 57776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mListener = listener; 57876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCueTexts = new Vector<String>(); 57976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 58076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 58176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar /* parsePercentageString */ 58276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public static float parseFloatPercentage(String s) 58376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throws NumberFormatException { 58476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!s.endsWith("%")) { 58576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("does not end in %"); 58676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 58776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar s = s.substring(0, s.length() - 1); 58876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // parseFloat allows an exponent or a sign 58976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (s.matches(".*[^0-9.].*")) { 59076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("contains an invalid character"); 59176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 59276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 59376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 59476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar float value = Float.parseFloat(s); 59576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (value < 0.0f || value > 100.0f) { 59676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("is out of range"); 59776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 59876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return value; 59976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 60076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("is not a number"); 60176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 60276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 60376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 60476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public static int parseIntPercentage(String s) throws NumberFormatException { 60576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!s.endsWith("%")) { 60676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("does not end in %"); 60776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 60876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar s = s.substring(0, s.length() - 1); 60976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // parseInt allows "-0" that returns 0, so check for non-digits 61076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (s.matches(".*[^0-9].*")) { 61176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("contains an invalid character"); 61276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 61376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 61476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 61576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int value = Integer.parseInt(s); 61676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (value < 0 || value > 100) { 61776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("is out of range"); 61876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 61976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return value; 62076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 62176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("is not a number"); 62276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 62376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 62476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 62576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public static long parseTimestampMs(String s) throws NumberFormatException { 62676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!s.matches("(\\d+:)?[0-5]\\d:[0-5]\\d\\.\\d{3}")) { 62776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar throw new NumberFormatException("has invalid format"); 62876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 62976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 63076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String[] parts = s.split("\\.", 2); 63176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar long value = 0; 63276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (String group: parts[0].split(":")) { 63376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar value = value * 60 + Long.parseLong(group); 63476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 63576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return value * 1000 + Long.parseLong(parts[1]); 63676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 63776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 63876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public static String timeToString(long timeMs) { 63976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return String.format("%d:%02d:%02d.%03d", 64076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar timeMs / 3600000, (timeMs / 60000) % 60, 64176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar (timeMs / 1000) % 60, timeMs % 1000); 64276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 64376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 64476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String s) { 64576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar boolean trailingCR = false; 64676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer = (mBuffer + s.replace("\0", "\ufffd")).replace("\r\n", "\n"); 64776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 64876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar /* keep trailing '\r' in case matching '\n' arrives in next packet */ 64976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mBuffer.endsWith("\r")) { 65076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar trailingCR = true; 65176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer = mBuffer.substring(0, mBuffer.length() - 1); 65276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 65376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 65476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String[] lines = mBuffer.split("[\r\n]"); 65576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (int i = 0; i < lines.length - 1; i++) { 65676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase.parse(lines[i]); 65776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 65876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 65976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer = lines[lines.length - 1]; 66076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (trailingCR) 66176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer += "\r"; 66276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 66376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 66476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void eos() { 66576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mBuffer.endsWith("\r")) { 66676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer = mBuffer.substring(0, mBuffer.length() - 1); 66776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 66876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 66976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase.parse(mBuffer); 67076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mBuffer = ""; 67176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 67276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar yieldCue(); 67376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseStart; 67476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 67576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 67676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void yieldCue() { 67776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mCue != null && mCueTexts.size() > 0) { 67876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mStrings = new String[mCueTexts.size()]; 67976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCueTexts.toArray(mCue.mStrings); 68076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCueTexts.clear(); 68176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mListener.onCueParsed(mCue); 68276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 68376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue = null; 68476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 68576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 68676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar interface Phase { 68776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void parse(String line); 68876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 68976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 69076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final private Phase mSkipRest = new Phase() { 69176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 69276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String line) { } 69376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar }; 69476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 69576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final private Phase mParseStart = new Phase() { // 5-9 69676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 69776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String line) { 698283fe37aa20d6f5910ed1c86847c6228e151e1ffLajos Molnar if (line.startsWith("\ufeff")) { 699283fe37aa20d6f5910ed1c86847c6228e151e1ffLajos Molnar line = line.substring(1); 700283fe37aa20d6f5910ed1c86847c6228e151e1ffLajos Molnar } 70176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!line.equals("WEBVTT") && 70276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar !line.startsWith("WEBVTT ") && 70376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar !line.startsWith("WEBVTT\t")) { 70476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("Not a WEBVTT header", line); 70576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mSkipRest; 70676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 70776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseHeader; 70876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 70976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 71076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar }; 71176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 71276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final private Phase mParseHeader = new Phase() { // 10-13 71376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackRegion parseRegion(String s) { 71476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackRegion region = new TextTrackRegion(); 71576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (String setting: s.split(" +")) { 71676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int equalAt = setting.indexOf('='); 71776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (equalAt <= 0 || equalAt == setting.length() - 1) { 71876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 71976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 72076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 72176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String name = setting.substring(0, equalAt); 72276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String value = setting.substring(equalAt + 1); 72376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (name.equals("id")) { 72476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mId = value; 72576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("width")) { 72676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 72776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mWidth = parseFloatPercentage(value); 72876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 72976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("region setting", name, 73076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "has invalid value", e.getMessage(), value); 73176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 73276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("lines")) { 73372bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar if (value.matches(".*[^0-9].*")) { 73472bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar log_warning("lines", name, "contains an invalid character", value); 73572bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar } else { 73672bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar try { 73772bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar region.mLines = Integer.parseInt(value); 73872bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar assert(region.mLines >= 0); // lines contains only digits 73972bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar } catch (NumberFormatException e) { 74072bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar log_warning("region setting", name, "is not numeric", value); 74176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 74276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 74376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("regionanchor") || 74476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar name.equals("viewportanchor")) { 74576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int commaAt = value.indexOf(","); 74676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (commaAt < 0) { 74776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("region setting", name, "contains no comma", value); 74876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 74976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 75076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 75176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String anchorX = value.substring(0, commaAt); 75276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String anchorY = value.substring(commaAt + 1); 75376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar float x, y; 75476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 75576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 75676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar x = parseFloatPercentage(anchorX); 75776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 75876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("region setting", name, 75976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "has invalid x component", e.getMessage(), anchorX); 76076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 76176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 76276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 76376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar y = parseFloatPercentage(anchorY); 76476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 76576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("region setting", name, 76676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "has invalid y component", e.getMessage(), anchorY); 76776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 76876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 76976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 77076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (name.charAt(0) == 'r') { 77176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mAnchorPointX = x; 77276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mAnchorPointY = y; 77376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 77476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mViewportAnchorPointX = x; 77576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mViewportAnchorPointY = y; 77676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 77776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("scroll")) { 77876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (value.equals("up")) { 77976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar region.mScrollValue = 78076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackRegion.SCROLL_VALUE_SCROLL_UP; 78176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 78276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("region setting", name, "has invalid value", value); 78376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 78476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 78576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 78676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return region; 78776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 78876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 78976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 79076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String line) { 79176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (line.length() == 0) { 79276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueId; 79376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (line.contains("-->")) { 79476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueTime; 79576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase.parse(line); 79676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 79776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int colonAt = line.indexOf(':'); 79876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (colonAt <= 0 || colonAt >= line.length() - 1) { 79976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("meta data header has invalid format", line); 80076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 80176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String name = line.substring(0, colonAt); 80276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String value = line.substring(colonAt + 1); 80376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 80476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (name.equals("Region")) { 80576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackRegion region = parseRegion(value); 80676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mListener.onRegionParsed(region); 80776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 80876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 80976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 81076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar }; 81176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 81276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final private Phase mParseCueId = new Phase() { 81376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 81476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String line) { 81576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (line.length() == 0) { 81676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return; 81776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 81876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 81976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar assert(mCue == null); 82076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 82176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (line.equals("NOTE") || line.startsWith("NOTE ")) { 82276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueText; 82376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 82476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 82576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue = new TextTrackCue(); 82676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCueTexts.clear(); 82776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 82876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueTime; 82976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (line.contains("-->")) { 83076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase.parse(line); 83176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 83276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mId = line; 83376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 83476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 83576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar }; 83676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 83776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final private Phase mParseCueTime = new Phase() { 83876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 83976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String line) { 84076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int arrowAt = line.indexOf("-->"); 84176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (arrowAt < 0) { 84276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue = null; 84376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueId; 84476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return; 84576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 84676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 84776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String start = line.substring(0, arrowAt).trim(); 84876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // convert only initial and first other white-space to space 84976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String rest = line.substring(arrowAt + 3) 85076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .replaceFirst("^\\s+", "").replaceFirst("\\s+", " "); 85176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int spaceAt = rest.indexOf(' '); 85276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String end = spaceAt > 0 ? rest.substring(0, spaceAt) : rest; 85376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar rest = spaceAt > 0 ? rest.substring(spaceAt + 1) : ""; 85476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 85576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mStartTimeMs = parseTimestampMs(start); 85676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mEndTimeMs = parseTimestampMs(end); 85776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (String setting: rest.split(" +")) { 85876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar int colonAt = setting.indexOf(':'); 85976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (colonAt <= 0 || colonAt == setting.length() - 1) { 86076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 86176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 86276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String name = setting.substring(0, colonAt); 86376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String value = setting.substring(colonAt + 1); 86476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 86576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (name.equals("region")) { 86676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mRegionId = value; 86776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("vertical")) { 86876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (value.equals("rl")) { 86976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mWritingDirection = 87076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCue.WRITING_DIRECTION_VERTICAL_RL; 87176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (value.equals("lr")) { 87276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mWritingDirection = 87376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCue.WRITING_DIRECTION_VERTICAL_LR; 87476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 87576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("cue setting", name, "has invalid value", value); 87676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 87776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("line")) { 87876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 87976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar /* TRICKY: we know that there are no spaces in value */ 88076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar assert(value.indexOf(' ') < 0); 88176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (value.endsWith("%")) { 88276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mSnapToLines = false; 88372bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar mCue.mLinePosition = parseIntPercentage(value); 88472bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar } else if (value.matches(".*[^0-9].*")) { 88572bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar log_warning("cue setting", name, 88672bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar "contains an invalid character", value); 88776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 88876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mSnapToLines = true; 88976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mLinePosition = Integer.parseInt(value); 89076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 89176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 89276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("cue setting", name, 89372bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar "is not numeric or percentage", value); 89476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 89572bbe6cca6470e86b56081c3fbe3cbb4360f5271Lajos Molnar // TODO: add support for optional alignment value [,start|middle|end] 89676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("position")) { 89776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 89876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mTextPosition = parseIntPercentage(value); 89976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 90076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("cue setting", name, 90176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "is not numeric or percentage", value); 90276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 90376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("size")) { 90476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 90576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mSize = parseIntPercentage(value); 90676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (NumberFormatException e) { 90776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("cue setting", name, 90876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar "is not numeric or percentage", value); 90976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 91076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (name.equals("align")) { 91176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (value.equals("start")) { 91276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mAlignment = TextTrackCue.ALIGNMENT_START; 91376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (value.equals("middle")) { 91476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mAlignment = TextTrackCue.ALIGNMENT_MIDDLE; 91576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (value.equals("end")) { 91676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mAlignment = TextTrackCue.ALIGNMENT_END; 91776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (value.equals("left")) { 91876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mAlignment = TextTrackCue.ALIGNMENT_LEFT; 91976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (value.equals("right")) { 92076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mAlignment = TextTrackCue.ALIGNMENT_RIGHT; 92176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 92276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar log_warning("cue setting", name, "has invalid value", value); 92376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar continue; 92476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 92576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 92676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 92776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 92876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mCue.mLinePosition != null || 92976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mSize != 100 || 93076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar (mCue.mWritingDirection != 93176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar TextTrackCue.WRITING_DIRECTION_HORIZONTAL)) { 93276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCue.mRegionId = ""; 93376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 93476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 93576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueText; 93676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 93776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar }; 93876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 93976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar /* also used for notes */ 94076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar final private Phase mParseCueText = new Phase() { 94176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 94276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void parse(String line) { 94376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (line.length() == 0) { 94476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar yieldCue(); 94576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mPhase = mParseCueId; 94676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return; 94776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else if (mCue != null) { 94876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mCueTexts.add(line); 94976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 95076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 95176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar }; 95276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 95376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private void log_warning( 95476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String nameType, String name, String message, 95576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String subMessage, String value) { 95676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Log.w(this.getClass().getName(), nameType + " '" + name + "' " + 95776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar message + " ('" + value + "' " + subMessage + ")"); 95876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 95976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 96076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private void log_warning( 96176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar String nameType, String name, String message, String value) { 96276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Log.w(this.getClass().getName(), nameType + " '" + name + "' " + 96376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar message + " ('" + value + "')"); 96476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 96576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 96676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private void log_warning(String message, String value) { 96776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Log.w(this.getClass().getName(), message + " ('" + value + "')"); 96876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 96976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 97076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 97176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar/** @hide */ 97276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarinterface WebVttCueListener { 97376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void onCueParsed(TextTrackCue cue); 97476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar void onRegionParsed(TextTrackRegion region); 97576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 97676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 97776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar/** @hide */ 97876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnarclass WebVttTrack extends SubtitleTrack implements WebVttCueListener { 97976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private static final String TAG = "WebVttTrack"; 98076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 98176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private final WebVttParser mParser = new WebVttParser(this); 98276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private final UnstyledTextExtractor mExtractor = 98376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar new UnstyledTextExtractor(); 98476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private final Tokenizer mTokenizer = new Tokenizer(mExtractor); 98576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private final Vector<Long> mTimestamps = new Vector<Long>(); 986d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final WebVttRenderingWidget mRenderingWidget; 98776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 98876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private final Map<String, TextTrackRegion> mRegions = 98976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar new HashMap<String, TextTrackRegion>(); 99076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar private Long mCurrentRunID; 99176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 992d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette WebVttTrack(WebVttRenderingWidget renderingWidget, MediaFormat format) { 99376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar super(format); 994d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 995d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mRenderingWidget = renderingWidget; 99676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 99776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 99876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 999d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public WebVttRenderingWidget getRenderingWidget() { 1000d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return mRenderingWidget; 100176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 100276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 100376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 1004079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang public void onData(byte[] data, boolean eos, long runID) { 1005079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang try { 1006079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang String str = new String(data, "UTF-8"); 1007079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang 1008079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang // implement intermixing restriction for WebVTT only for now 1009079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang synchronized(mParser) { 1010079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang if (mCurrentRunID != null && runID != mCurrentRunID) { 1011079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang throw new IllegalStateException( 1012079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang "Run #" + mCurrentRunID + 1013079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang " in progress. Cannot process run #" + runID); 1014079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang } 1015079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang mCurrentRunID = runID; 1016079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang mParser.parse(str); 1017079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang if (eos) { 1018079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang finishedRun(runID); 1019079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang mParser.eos(); 1020079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang mRegions.clear(); 1021079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang mCurrentRunID = null; 1022079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang } 102376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 1024079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang } catch (java.io.UnsupportedEncodingException e) { 1025079fa9683dc062f154333a661f5e84a5ac5e43c7Chong Zhang Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e); 102676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 102776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 102876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 102976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 103076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void onCueParsed(TextTrackCue cue) { 103176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar synchronized (mParser) { 103276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // resolve region 103376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (cue.mRegionId.length() != 0) { 103476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.mRegion = mRegions.get(cue.mRegionId); 103576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 103676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 103776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (DEBUG) Log.v(TAG, "adding cue " + cue); 103876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 103976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // tokenize text track string-lines into lines of spans 104076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTokenizer.reset(); 104176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (String s: cue.mStrings) { 104276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTokenizer.tokenize(s); 104376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 104476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.mLines = mExtractor.getText(); 104576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (DEBUG) Log.v(TAG, cue.appendLinesToBuilder( 104676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.appendStringsToBuilder( 104776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar new StringBuilder()).append(" simplified to: ")) 104876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar .toString()); 104976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 105076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // extract inner timestamps 105176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (TextTrackCueSpan[] line: cue.mLines) { 105276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (TextTrackCueSpan span: line) { 105376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (span.mTimestampMs > cue.mStartTimeMs && 105476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar span.mTimestampMs < cue.mEndTimeMs && 105576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar !mTimestamps.contains(span.mTimestampMs)) { 105676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTimestamps.add(span.mTimestampMs); 105776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 105876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 105976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 106076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 106176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (mTimestamps.size() > 0) { 106276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.mInnerTimesMs = new long[mTimestamps.size()]; 106376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar for (int ix=0; ix < mTimestamps.size(); ++ix) { 106476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.mInnerTimesMs[ix] = mTimestamps.get(ix); 106576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 106676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mTimestamps.clear(); 106776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } else { 106876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.mInnerTimesMs = null; 106976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 107076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 107176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar cue.mRunID = mCurrentRunID; 107276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 107376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 107476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar addCue(cue); 107576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 107676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 107776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar @Override 107876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void onRegionParsed(TextTrackRegion region) { 107976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar synchronized(mParser) { 108076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar mRegions.put(region.mId, region); 108176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 108276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 108376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 1084d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 108576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar public void updateView(Vector<SubtitleTrack.Cue> activeCues) { 108676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (!mVisible) { 108776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar // don't keep the state if we are not visible 108876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar return; 108976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 109076935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 109176935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar if (DEBUG && mTimeProvider != null) { 109276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar try { 109376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Log.d(TAG, "at " + 109476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar (mTimeProvider.getCurrentTimeUs(false, true) / 1000) + 109576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar " ms the active cues are:"); 109676935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } catch (IllegalStateException e) { 109776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar Log.d(TAG, "at (illegal state) the active cues are:"); 109876935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 109976935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 1100d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 11013cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih if (mRenderingWidget != null) { 11023cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih mRenderingWidget.setActiveCues(activeCues); 11033cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1104d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1105d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette} 1106d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1107d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette/** 1108d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Widget capable of rendering WebVTT captions. 1109d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 1110d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @hide 1111d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1112d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteclass WebVttRenderingWidget extends ViewGroup implements SubtitleTrack.RenderingWidget { 1113d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static final boolean DEBUG = false; 1114e88aee8ad85b01229b12dbc0c3cc2f0b8b490192Alan Viverette 1115e88aee8ad85b01229b12dbc0c3cc2f0b8b490192Alan Viverette private static final CaptionStyle DEFAULT_CAPTION_STYLE = CaptionStyle.DEFAULT; 1116e88aee8ad85b01229b12dbc0c3cc2f0b8b490192Alan Viverette 1117d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static final int DEBUG_REGION_BACKGROUND = 0x800000FF; 1118d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static final int DEBUG_CUE_BACKGROUND = 0x80FF0000; 1119d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1120d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** WebVtt specifies line height as 5.3% of the viewport height. */ 1121d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static final float LINE_HEIGHT_RATIO = 0.0533f; 1122d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1123d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Map of active regions, used to determine enter/exit. */ 1124d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final ArrayMap<TextTrackRegion, RegionLayout> mRegionBoxes = 1125d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette new ArrayMap<TextTrackRegion, RegionLayout>(); 1126d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1127d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Map of active cues, used to determine enter/exit. */ 1128d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final ArrayMap<TextTrackCue, CueLayout> mCueBoxes = 1129d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette new ArrayMap<TextTrackCue, CueLayout>(); 1130d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1131d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Captioning manager, used to obtain and track caption properties. */ 1132d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final CaptioningManager mManager; 1133d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1134d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Callback for rendering changes. */ 1135d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private OnChangedListener mListener; 1136d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1137d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Current caption style. */ 1138d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private CaptionStyle mCaptionStyle; 1139d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1140d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Current font size, computed from font scaling factor and height. */ 1141d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private float mFontSize; 1142d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1143d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Whether a caption style change listener is registered. */ 1144d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private boolean mHasChangeListener; 1145d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1146d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public WebVttRenderingWidget(Context context) { 1147d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette this(context, null); 1148d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1149d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1150d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public WebVttRenderingWidget(Context context, AttributeSet attrs) { 1151d6479ec5eec13914f656f6be996d95fe1610fd57Alan Viverette this(context, attrs, 0); 1152d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1153d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1154617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public WebVttRenderingWidget(Context context, AttributeSet attrs, int defStyleAttr) { 1155617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette this(context, attrs, defStyleAttr, 0); 1156617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette } 1157617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette 1158e88aee8ad85b01229b12dbc0c3cc2f0b8b490192Alan Viverette public WebVttRenderingWidget( 1159e88aee8ad85b01229b12dbc0c3cc2f0b8b490192Alan Viverette Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 1160617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette super(context, attrs, defStyleAttr, defStyleRes); 1161d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1162d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Cannot render text over video when layer type is hardware. 1163d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setLayerType(View.LAYER_TYPE_SOFTWARE, null); 1164d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1165d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mManager = (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE); 1166d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCaptionStyle = mManager.getUserStyle(); 1167d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mFontSize = mManager.getFontScale() * getHeight() * LINE_HEIGHT_RATIO; 1168d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1169d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1170d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1171d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setSize(int width, int height) { 1172d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); 1173d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); 1174d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1175d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette measure(widthSpec, heightSpec); 1176d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette layout(0, 0, width, height); 1177d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1178d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1179d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1180d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onAttachedToWindow() { 1181d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onAttachedToWindow(); 1182d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1183d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette manageChangeListener(); 1184d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1185d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1186d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1187d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onDetachedFromWindow() { 1188d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onDetachedFromWindow(); 1189d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1190d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette manageChangeListener(); 1191d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1192d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1193d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1194d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setOnChangedListener(OnChangedListener listener) { 1195d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mListener = listener; 1196d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1197d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1198d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1199d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setVisible(boolean visible) { 1200d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (visible) { 1201d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setVisibility(View.VISIBLE); 1202d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 1203d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setVisibility(View.GONE); 1204d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1205d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1206d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette manageChangeListener(); 1207d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1208d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1209d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1210d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Manages whether this renderer is listening for caption style changes. 1211d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1212d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void manageChangeListener() { 1213d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final boolean needsListener = isAttachedToWindow() && getVisibility() == View.VISIBLE; 1214d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mHasChangeListener != needsListener) { 1215d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mHasChangeListener = needsListener; 1216d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1217d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (needsListener) { 1218d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mManager.addCaptioningChangeListener(mCaptioningListener); 1219d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1220d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CaptionStyle captionStyle = mManager.getUserStyle(); 1221d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float fontSize = mManager.getFontScale() * getHeight() * LINE_HEIGHT_RATIO; 1222d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setCaptionStyle(captionStyle, fontSize); 1223d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 1224d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mManager.removeCaptioningChangeListener(mCaptioningListener); 1225d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1226d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1227d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1228d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1229d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setActiveCues(Vector<SubtitleTrack.Cue> activeCues) { 1230d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final Context context = getContext(); 1231d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CaptionStyle captionStyle = mCaptionStyle; 1232d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float fontSize = mFontSize; 1233d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1234d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette prepForPrune(); 1235d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1236d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Ensure we have all necessary cue and region boxes. 1237d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int count = activeCues.size(); 1238d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < count; i++) { 1239d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCue cue = (TextTrackCue) activeCues.get(i); 1240d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackRegion region = cue.mRegion; 1241d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (region != null) { 1242d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette RegionLayout regionBox = mRegionBoxes.get(region); 1243d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (regionBox == null) { 1244d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionBox = new RegionLayout(context, region, captionStyle, fontSize); 1245d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mRegionBoxes.put(region, regionBox); 1246d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette addView(regionBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 124776935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 1248d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionBox.put(cue); 1249d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 1250d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette CueLayout cueBox = mCueBoxes.get(cue); 1251d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (cueBox == null) { 1252d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox = new CueLayout(context, cue, captionStyle, fontSize); 1253d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCueBoxes.put(cue, cueBox); 1254d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette addView(cueBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 125576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 1256d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.update(); 1257d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.setOrder(i); 1258d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1259d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1260d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1261d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette prune(); 1262d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1263d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Force measurement and layout. 1264d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int width = getWidth(); 1265d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int height = getHeight(); 1266d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setSize(width, height); 1267d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1268d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mListener != null) { 1269d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mListener.onChanged(this); 1270d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1271d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1272d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1273d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void setCaptionStyle(CaptionStyle captionStyle, float fontSize) { 1274e88aee8ad85b01229b12dbc0c3cc2f0b8b490192Alan Viverette captionStyle = DEFAULT_CAPTION_STYLE.applyStyle(captionStyle); 1275d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCaptionStyle = captionStyle; 1276d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mFontSize = fontSize; 1277d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1278d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mCueBoxes.size(); 1279d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1280d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mCueBoxes.valueAt(i); 1281d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.setCaptionStyle(captionStyle, fontSize); 1282d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1283d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1284d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int regionCount = mRegionBoxes.size(); 1285d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < regionCount; i++) { 1286d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final RegionLayout regionBox = mRegionBoxes.valueAt(i); 1287d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionBox.setCaptionStyle(captionStyle, fontSize); 1288d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1289d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1290d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1291d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1292d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Remove inactive cues and regions. 1293d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1294d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void prune() { 1295d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int regionCount = mRegionBoxes.size(); 1296d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < regionCount; i++) { 1297d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final RegionLayout regionBox = mRegionBoxes.valueAt(i); 1298d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (regionBox.prune()) { 1299d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette removeView(regionBox); 1300d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mRegionBoxes.removeAt(i); 1301d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionCount--; 1302d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette i--; 130376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 130476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 130576935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar 1306d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int cueCount = mCueBoxes.size(); 1307d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1308d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mCueBoxes.valueAt(i); 1309d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (!cueBox.isActive()) { 1310d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette removeView(cueBox); 1311d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCueBoxes.removeAt(i); 1312d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueCount--; 1313d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette i--; 1314d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1315d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1316d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1317d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1318d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1319d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Reset active cues and regions. 1320d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1321d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void prepForPrune() { 1322d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int regionCount = mRegionBoxes.size(); 1323d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < regionCount; i++) { 1324d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final RegionLayout regionBox = mRegionBoxes.valueAt(i); 1325d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionBox.prepForPrune(); 1326d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1327d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1328d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mCueBoxes.size(); 1329d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1330d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mCueBoxes.valueAt(i); 1331d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.prepForPrune(); 1332d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1333d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1334d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1335d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1336d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1337d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onMeasure(widthMeasureSpec, heightMeasureSpec); 1338d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1339d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int regionCount = mRegionBoxes.size(); 1340d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < regionCount; i++) { 1341d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final RegionLayout regionBox = mRegionBoxes.valueAt(i); 1342d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionBox.measureForParent(widthMeasureSpec, heightMeasureSpec); 1343d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1344d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1345d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mCueBoxes.size(); 1346d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1347d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mCueBoxes.valueAt(i); 1348d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.measureForParent(widthMeasureSpec, heightMeasureSpec); 1349d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1350d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1351d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1352d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1353d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette protected void onLayout(boolean changed, int l, int t, int r, int b) { 1354d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int viewportWidth = r - l; 1355d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int viewportHeight = b - t; 1356d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1357d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setCaptionStyle(mCaptionStyle, 1358d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mManager.getFontScale() * LINE_HEIGHT_RATIO * viewportHeight); 1359d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1360d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int regionCount = mRegionBoxes.size(); 1361d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < regionCount; i++) { 1362d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final RegionLayout regionBox = mRegionBoxes.valueAt(i); 1363d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette layoutRegion(viewportWidth, viewportHeight, regionBox); 1364d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1365d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1366d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mCueBoxes.size(); 1367d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1368d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mCueBoxes.valueAt(i); 1369d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette layoutCue(viewportWidth, viewportHeight, cueBox); 1370d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1371d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1372d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1373d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1374d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Lays out a region within the viewport. The region handles layout for 1375d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * contained cues. 1376d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1377d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void layoutRegion( 1378d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int viewportWidth, int viewportHeight, 1379d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette RegionLayout regionBox) { 1380d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackRegion region = regionBox.getRegion(); 1381d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int regionHeight = regionBox.getMeasuredHeight(); 1382d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int regionWidth = regionBox.getMeasuredWidth(); 1383d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1384d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // TODO: Account for region anchor point. 1385d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float x = region.mViewportAnchorPointX; 1386d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float y = region.mViewportAnchorPointY; 1387d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int left = (int) (x * (viewportWidth - regionWidth) / 100); 1388d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int top = (int) (y * (viewportHeight - regionHeight) / 100); 1389d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1390d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette regionBox.layout(left, top, left + regionWidth, top + regionHeight); 1391d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1392d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1393d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1394d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Lays out a cue within the viewport. 1395d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1396d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void layoutCue( 1397d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int viewportWidth, int viewportHeight, CueLayout cueBox) { 1398d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCue cue = cueBox.getCue(); 1399d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int direction = getLayoutDirection(); 1400d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int absAlignment = resolveCueAlignment(direction, cue.mAlignment); 1401d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final boolean cueSnapToLines = cue.mSnapToLines; 1402d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1403d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int size = 100 * cueBox.getMeasuredWidth() / viewportWidth; 1404d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1405d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Determine raw x-position. 1406d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int xPosition; 1407d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette switch (absAlignment) { 1408d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_LEFT: 1409d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette xPosition = cue.mTextPosition; 1410d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1411d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_RIGHT: 1412d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette xPosition = cue.mTextPosition - size; 1413d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1414d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_MIDDLE: 1415d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette default: 1416d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette xPosition = cue.mTextPosition - size / 2; 1417d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1418d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1419d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1420d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Adjust x-position for layout. 1421d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (direction == LAYOUT_DIRECTION_RTL) { 1422d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette xPosition = 100 - xPosition; 1423d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1424d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1425d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // If the text track cue snap-to-lines flag is set, adjust 1426d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // x-position and size for padding. This is equivalent to placing the 1427d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // cue within the title-safe area. 1428d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (cueSnapToLines) { 1429d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int paddingLeft = 100 * getPaddingLeft() / viewportWidth; 1430d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int paddingRight = 100 * getPaddingRight() / viewportWidth; 1431d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (xPosition < paddingLeft && xPosition + size > paddingLeft) { 1432d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette xPosition += paddingLeft; 1433d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette size -= paddingLeft; 1434d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1435d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float rightEdge = 100 - paddingRight; 1436d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (xPosition < rightEdge && xPosition + size > rightEdge) { 1437d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette size -= paddingRight; 1438d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1439d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1440d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1441d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Compute absolute left position and width. 1442d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int left = xPosition * viewportWidth / 100; 1443d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int width = size * viewportWidth / 100; 1444d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1445d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Determine initial y-position. 1446d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int yPosition = calculateLinePosition(cueBox); 1447d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1448d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Compute absolute final top position and height. 1449d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int height = cueBox.getMeasuredHeight(); 1450d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int top; 1451d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (yPosition < 0) { 1452d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // TODO: This needs to use the actual height of prior boxes. 1453d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette top = viewportHeight + yPosition * height; 1454d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 1455d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette top = yPosition * (viewportHeight - height) / 100; 1456d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1457d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1458d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Layout cue in final position. 1459d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.layout(left, top, left + width, top + height); 1460d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1461d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1462d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1463d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Calculates the line position for a cue. 1464d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * <p> 1465d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * If the resulting position is negative, it represents a bottom-aligned 1466d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * position relative to the number of active cues. Otherwise, it represents 1467d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * a percentage [0-100] of the viewport height. 1468d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1469d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private int calculateLinePosition(CueLayout cueBox) { 1470d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCue cue = cueBox.getCue(); 1471d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final Integer linePosition = cue.mLinePosition; 1472d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final boolean snapToLines = cue.mSnapToLines; 1473d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final boolean autoPosition = (linePosition == null); 1474d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1475d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (!snapToLines && !autoPosition && (linePosition < 0 || linePosition > 100)) { 1476d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Invalid line position defaults to 100. 1477d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return 100; 1478d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else if (!autoPosition) { 1479d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Use the valid, supplied line position. 1480d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return linePosition; 1481d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else if (!snapToLines) { 1482d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Automatic, non-snapped line position defaults to 100. 1483d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return 100; 1484d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 1485d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Automatic snapped line position uses active cue order. 1486d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return -(cueBox.mOrder + 1); 1487d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1488d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1489d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1490d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1491d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Resolves cue alignment according to the specified layout direction. 1492d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1493d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static int resolveCueAlignment(int layoutDirection, int alignment) { 1494d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette switch (alignment) { 1495d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_START: 1496d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return layoutDirection == View.LAYOUT_DIRECTION_LTR ? 1497d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette TextTrackCue.ALIGNMENT_LEFT : TextTrackCue.ALIGNMENT_RIGHT; 1498d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_END: 1499d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return layoutDirection == View.LAYOUT_DIRECTION_LTR ? 1500d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette TextTrackCue.ALIGNMENT_RIGHT : TextTrackCue.ALIGNMENT_LEFT; 1501d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1502d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return alignment; 1503d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1504d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1505d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final CaptioningChangeListener mCaptioningListener = new CaptioningChangeListener() { 1506d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1507d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onFontScaleChanged(float fontScale) { 1508d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float fontSize = fontScale * getHeight() * LINE_HEIGHT_RATIO; 1509d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setCaptionStyle(mCaptionStyle, fontSize); 1510d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1511d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1512d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1513d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onUserStyleChanged(CaptionStyle userStyle) { 1514d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setCaptionStyle(userStyle, mFontSize); 1515d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1516d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette }; 1517d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1518d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1519d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * A text track region represents a portion of the video viewport and 1520d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * provides a rendering area for text track cues. 1521d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1522d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static class RegionLayout extends LinearLayout { 1523d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final ArrayList<CueLayout> mRegionCueBoxes = new ArrayList<CueLayout>(); 1524d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final TextTrackRegion mRegion; 1525d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1526d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private CaptionStyle mCaptionStyle; 1527d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private float mFontSize; 1528d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1529d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public RegionLayout(Context context, TextTrackRegion region, CaptionStyle captionStyle, 1530d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette float fontSize) { 1531d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super(context); 1532d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1533d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mRegion = region; 1534d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCaptionStyle = captionStyle; 1535d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mFontSize = fontSize; 1536d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1537d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // TODO: Add support for vertical text 1538d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setOrientation(VERTICAL); 1539d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1540d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (DEBUG) { 1541d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setBackgroundColor(DEBUG_REGION_BACKGROUND); 154255d70620d9fda8afafb2fdec59757a710eec0e89Alan Viverette } else { 154355d70620d9fda8afafb2fdec59757a710eec0e89Alan Viverette setBackgroundColor(captionStyle.windowColor); 1544d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1545d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1546d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1547d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setCaptionStyle(CaptionStyle captionStyle, float fontSize) { 1548d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCaptionStyle = captionStyle; 1549d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mFontSize = fontSize; 1550d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1551d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mRegionCueBoxes.size(); 1552d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1553d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mRegionCueBoxes.get(i); 1554d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.setCaptionStyle(captionStyle, fontSize); 1555d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 155655d70620d9fda8afafb2fdec59757a710eec0e89Alan Viverette 155755d70620d9fda8afafb2fdec59757a710eec0e89Alan Viverette setBackgroundColor(captionStyle.windowColor); 1558d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1559d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1560d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1561d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Performs the parent's measurement responsibilities, then 1562d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * automatically performs its own measurement. 1563d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1564d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void measureForParent(int widthMeasureSpec, int heightMeasureSpec) { 1565d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackRegion region = mRegion; 1566d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int specWidth = MeasureSpec.getSize(widthMeasureSpec); 1567d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int specHeight = MeasureSpec.getSize(heightMeasureSpec); 1568d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int width = (int) region.mWidth; 1569d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1570d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Determine the absolute maximum region size as the requested size. 1571d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int size = width * specWidth / 100; 1572d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1573d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette widthMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST); 1574d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette heightMeasureSpec = MeasureSpec.makeMeasureSpec(specHeight, MeasureSpec.AT_MOST); 1575d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette measure(widthMeasureSpec, heightMeasureSpec); 1576d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1577d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1578d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1579d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Prepares this region for pruning by setting all tracks as inactive. 1580d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * <p> 1581d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Tracks that are added or updated using {@link #put(TextTrackCue)} 1582d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * after this calling this method will be marked as active. 1583d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1584d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void prepForPrune() { 1585d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mRegionCueBoxes.size(); 1586d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1587d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mRegionCueBoxes.get(i); 1588d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.prepForPrune(); 1589d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1590d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1591d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1592d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1593d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Adds a {@link TextTrackCue} to this region. If the track had already 1594d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * been added, updates its active state. 1595d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 1596d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @param cue 1597d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1598d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void put(TextTrackCue cue) { 1599d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int cueCount = mRegionCueBoxes.size(); 1600d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1601d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mRegionCueBoxes.get(i); 1602d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (cueBox.getCue() == cue) { 1603d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueBox.update(); 1604d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return; 1605d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1606d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1607d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1608d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = new CueLayout(getContext(), cue, mCaptionStyle, mFontSize); 16097fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette mRegionCueBoxes.add(cueBox); 1610d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette addView(cueBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 1611d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1612d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (getChildCount() > mRegion.mLines) { 1613d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette removeViewAt(0); 1614d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1615d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1616d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1617d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1618d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Remove all inactive tracks from this region. 1619d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 1620d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @return true if this region is empty and should be pruned 1621d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1622d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public boolean prune() { 1623d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette int cueCount = mRegionCueBoxes.size(); 1624d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < cueCount; i++) { 1625d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CueLayout cueBox = mRegionCueBoxes.get(i); 1626d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (!cueBox.isActive()) { 1627d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mRegionCueBoxes.remove(i); 1628d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette removeView(cueBox); 1629d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette cueCount--; 1630d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette i--; 1631d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1632d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1633d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1634d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return mRegionCueBoxes.isEmpty(); 1635d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1636d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1637d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1638d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @return the region data backing this layout 1639d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1640d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public TextTrackRegion getRegion() { 1641d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return mRegion; 1642d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1643d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1644d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1645d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1646d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * A text track cue is the unit of time-sensitive data in a text track, 1647d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * corresponding for instance for subtitles and captions to the text that 1648d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * appears at a particular time and disappears at another time. 1649d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * <p> 1650d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * A single cue may contain multiple {@link SpanLayout}s, each representing a 1651d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * single line of text. 1652d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1653d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static class CueLayout extends LinearLayout { 1654d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public final TextTrackCue mCue; 1655d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1656d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private CaptionStyle mCaptionStyle; 1657d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private float mFontSize; 1658d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1659d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private boolean mActive; 1660d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private int mOrder; 1661d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1662d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public CueLayout( 1663d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette Context context, TextTrackCue cue, CaptionStyle captionStyle, float fontSize) { 1664d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super(context); 1665d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1666d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCue = cue; 1667d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCaptionStyle = captionStyle; 1668d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mFontSize = fontSize; 1669d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1670d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // TODO: Add support for vertical text. 1671d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final boolean horizontal = cue.mWritingDirection 1672d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette == TextTrackCue.WRITING_DIRECTION_HORIZONTAL; 1673d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setOrientation(horizontal ? VERTICAL : HORIZONTAL); 1674d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1675d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette switch (cue.mAlignment) { 1676d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_END: 1677d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setGravity(Gravity.END); 1678d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1679d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_LEFT: 1680d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setGravity(Gravity.LEFT); 1681d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1682d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_MIDDLE: 1683d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setGravity(horizontal 1684d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette ? Gravity.CENTER_HORIZONTAL : Gravity.CENTER_VERTICAL); 1685d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1686d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_RIGHT: 1687d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setGravity(Gravity.RIGHT); 1688d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1689d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_START: 1690d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setGravity(Gravity.START); 1691d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1692d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1693d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1694d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (DEBUG) { 1695d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setBackgroundColor(DEBUG_CUE_BACKGROUND); 1696d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1697d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1698d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette update(); 1699d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1700d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1701d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setCaptionStyle(CaptionStyle style, float fontSize) { 1702d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mCaptionStyle = style; 1703d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mFontSize = fontSize; 1704d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1705d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int n = getChildCount(); 1706d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < n; i++) { 1707d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final View child = getChildAt(i); 1708d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (child instanceof SpanLayout) { 1709d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette ((SpanLayout) child).setCaptionStyle(style, fontSize); 1710d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1711d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1712d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1713d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1714d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void prepForPrune() { 1715d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mActive = false; 1716d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1717d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1718d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void update() { 1719d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mActive = true; 1720d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1721d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette removeAllViews(); 1722d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 17237fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette final int cueAlignment = resolveCueAlignment(getLayoutDirection(), mCue.mAlignment); 17247fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette final Alignment alignment; 17257fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette switch (cueAlignment) { 17267fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette case TextTrackCue.ALIGNMENT_LEFT: 17277fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette alignment = Alignment.ALIGN_LEFT; 17287fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette break; 17297fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette case TextTrackCue.ALIGNMENT_RIGHT: 17307fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette alignment = Alignment.ALIGN_RIGHT; 17317fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette break; 17327fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette case TextTrackCue.ALIGNMENT_MIDDLE: 17337fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette default: 17347fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette alignment = Alignment.ALIGN_CENTER; 17357fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette } 17367fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette 1737d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final CaptionStyle captionStyle = mCaptionStyle; 1738d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final float fontSize = mFontSize; 1739d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCueSpan[][] lines = mCue.mLines; 1740d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int lineCount = lines.length; 1741d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < lineCount; i++) { 1742d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final SpanLayout lineBox = new SpanLayout(getContext(), lines[i]); 17437fe420f31b4de2bbd7a89194384d0c9ac6293226Alan Viverette lineBox.setAlignment(alignment); 1744d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette lineBox.setCaptionStyle(captionStyle, fontSize); 1745d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1746d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette addView(lineBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 1747d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1748d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1749d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1750d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 1751d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1752d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onMeasure(widthMeasureSpec, heightMeasureSpec); 1753d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1754d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1755d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1756d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Performs the parent's measurement responsibilities, then 1757d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * automatically performs its own measurement. 1758d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1759d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void measureForParent(int widthMeasureSpec, int heightMeasureSpec) { 1760d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCue cue = mCue; 1761d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int specWidth = MeasureSpec.getSize(widthMeasureSpec); 1762d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int specHeight = MeasureSpec.getSize(heightMeasureSpec); 1763d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int direction = getLayoutDirection(); 1764d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int absAlignment = resolveCueAlignment(direction, cue.mAlignment); 1765d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1766d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Determine the maximum size of cue based on its starting position 1767d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // and the direction in which it grows. 1768d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int maximumSize; 1769d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette switch (absAlignment) { 1770d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_LEFT: 1771d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette maximumSize = 100 - cue.mTextPosition; 1772d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1773d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_RIGHT: 1774d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette maximumSize = cue.mTextPosition; 1775d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1776d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette case TextTrackCue.ALIGNMENT_MIDDLE: 1777d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (cue.mTextPosition <= 50) { 1778d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette maximumSize = cue.mTextPosition * 2; 1779d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 1780d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette maximumSize = (100 - cue.mTextPosition) * 2; 1781d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1782d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette break; 1783d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette default: 1784d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette maximumSize = 0; 1785d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1786d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1787d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // Determine absolute maximum cue size as the smaller of the 1788d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette // requested size and the maximum theoretical size. 1789d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int size = Math.min(cue.mSize, maximumSize) * specWidth / 100; 1790d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette widthMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST); 1791d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette heightMeasureSpec = MeasureSpec.makeMeasureSpec(specHeight, MeasureSpec.AT_MOST); 1792d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette measure(widthMeasureSpec, heightMeasureSpec); 1793d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1794d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1795d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1796d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Sets the order of this cue in the list of active cues. 1797d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 1798d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @param order the order of this cue in the list of active cues 1799d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1800d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setOrder(int order) { 1801d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mOrder = order; 1802d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1803d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1804d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1805d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @return whether this cue is marked as active 1806d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1807d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public boolean isActive() { 1808d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return mActive; 1809d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1810d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1811d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1812d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @return the cue data backing this layout 1813d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1814d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public TextTrackCue getCue() { 1815d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette return mCue; 1816d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1817d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1818d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1819d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 1820d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * A text track line represents a single line of text within a cue. 1821d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * <p> 1822d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * A single line may contain multiple spans, each representing a section of 1823d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * text that may be enabled or disabled at a particular time. 1824d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 1825d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private static class SpanLayout extends SubtitleView { 1826d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final SpannableStringBuilder mBuilder = new SpannableStringBuilder(); 1827d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private final TextTrackCueSpan[] mSpans; 1828d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1829d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public SpanLayout(Context context, TextTrackCueSpan[] spans) { 1830d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super(context); 1831d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1832d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSpans = spans; 1833d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1834d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette update(); 1835d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1836d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1837d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void update() { 1838d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final SpannableStringBuilder builder = mBuilder; 1839d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCueSpan[] spans = mSpans; 1840d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1841d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette builder.clear(); 1842d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette builder.clearSpans(); 1843d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1844d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int spanCount = spans.length; 1845d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette for (int i = 0; i < spanCount; i++) { 1846d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final TextTrackCueSpan span = spans[i]; 1847d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (span.mEnabled) { 1848d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette builder.append(spans[i].mText); 1849d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1850d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1851d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1852d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setText(builder); 1853d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 1854d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 1855d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setCaptionStyle(CaptionStyle captionStyle, float fontSize) { 1856d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setBackgroundColor(captionStyle.backgroundColor); 1857d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setForegroundColor(captionStyle.foregroundColor); 1858d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setEdgeColor(captionStyle.edgeColor); 1859d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setEdgeType(captionStyle.edgeType); 1860d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setTypeface(captionStyle.getTypeface()); 1861d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setTextSize(fontSize); 186276935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 186376935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar } 186476935a5890ed8dd9d47f76f7593cc1c14c3844dbLajos Molnar} 1865