103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar/* 203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * Copyright (C) 2013 The Android Open Source Project 303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * 403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * Licensed under the Apache License, Version 2.0 (the "License"); 503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * you may not use this file except in compliance with the License. 603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * You may obtain a copy of the License at 703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * 803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * http://www.apache.org/licenses/LICENSE-2.0 903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * 1003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * Unless required by applicable law or agreed to in writing, software 1103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * distributed under the License is distributed on an "AS IS" BASIS, 1203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * See the License for the specific language governing permissions and 1403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * limitations under the License. 1503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar */ 1603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 1703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnarpackage android.media; 1803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 19d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteimport android.graphics.Canvas; 2003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnarimport android.os.Handler; 2103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnarimport android.util.Log; 2203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnarimport android.util.LongSparseArray; 2303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnarimport android.util.Pair; 2403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 2503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnarimport java.util.Iterator; 2603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnarimport java.util.NoSuchElementException; 2703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnarimport java.util.SortedMap; 2803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnarimport java.util.TreeMap; 2903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnarimport java.util.Vector; 3003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 3103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar/** 3203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * A subtitle track abstract base class that is responsible for parsing and displaying 3303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * an instance of a particular type of subtitle. 3403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * 3503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * @hide 3603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar */ 3703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnarpublic abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeListener { 3803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private static final String TAG = "SubtitleTrack"; 3903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private long mLastUpdateTimeMs; 4003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private long mLastTimeMs; 4103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 4203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private Runnable mRunnable; 4303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 4403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide TODO private */ 4503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar final protected LongSparseArray<Run> mRunsByEndTime = new LongSparseArray<Run>(); 4603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide TODO private */ 4703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar final protected LongSparseArray<Run> mRunsByID = new LongSparseArray<Run>(); 4803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 4903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide TODO private */ 5003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar protected CueList mCues; 5103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide TODO private */ 5203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar final protected Vector<Cue> mActiveCues = new Vector<Cue>(); 5303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 5403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar protected boolean mVisible; 5503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 5603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 5703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public boolean DEBUG = false; 5803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 5903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 6003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar protected Handler mHandler = new Handler(); 6103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 6203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private MediaFormat mFormat; 6303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 6403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public SubtitleTrack(MediaFormat format) { 6503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mFormat = format; 6603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mCues = new CueList(); 6703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar clearActiveCues(); 6803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mLastTimeMs = -1; 6903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 7003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 7103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 72d486f9656a6f9d6c056d84fce39f3db8d1614e1dLajos Molnar public final MediaFormat getFormat() { 7303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return mFormat; 7403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 7503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 7603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private long mNextScheduledTimeMs = -1; 7703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 7803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** 7903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * Called when there is input data for the subtitle track. The 8003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * complete subtitle for a track can include multiple whole units 8103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * (runs). Each of these units can have multiple sections. The 8203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * contents of a run are submitted in sequential order, with eos 8303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * indicating the last section of the run. Calls from different 8403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * runs must not be intermixed. 8503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * 8603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * @param data 8703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * @param eos true if this is the last section of the run. 8803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * @param runID mostly-unique ID for this run of data. Subtitle cues 8903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * with runID of 0 are discarded immediately after 9003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * display. Cues with runID of ~0 are discarded 9103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * only at the deletion of the track object. Cues 9203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * with other runID-s are discarded at the end of the 9303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * run, which defaults to the latest timestamp of 9403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * any of its cues (with this runID). 9503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * 9603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * TODO use ByteBuffer 9703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar */ 9803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public abstract void onData(String data, boolean eos, long runID); 9903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 10003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** 101d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Called when adding the subtitle rendering widget to the view hierarchy, 102d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * as well as when showing or hiding the subtitle track, or when the video 10303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * surface position has changed. 10403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * 105d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @return the widget that renders this subtitle track. For most renderers 106d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * there should be a single shared instance that is used for all 107d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * tracks supported by that renderer, as at most one subtitle track 108d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * is visible at one time. 10903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar */ 110d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public abstract RenderingWidget getRenderingWidget(); 11103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 11203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** 11303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * Called when the active cues have changed, and the contents of the subtitle 11403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * view should be updated. 11503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * 11603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * @hide 11703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar */ 11803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public abstract void updateView(Vector<Cue> activeCues); 11903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 12003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 12103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar protected synchronized void updateActiveCues(boolean rebuild, long timeMs) { 12203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // out-of-order times mean seeking or new active cues being added 12303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // (during their own timespan) 12403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (rebuild || mLastUpdateTimeMs > timeMs) { 12503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar clearActiveCues(); 12603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 12703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 12803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar for(Iterator<Pair<Long, Cue> > it = 12903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mCues.entriesBetween(mLastUpdateTimeMs, timeMs).iterator(); it.hasNext(); ) { 13003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Pair<Long, Cue> event = it.next(); 13103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Cue cue = event.second; 13203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 13303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (cue.mEndTimeMs == event.first) { 13403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // remove past cues 13503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (DEBUG) Log.v(TAG, "Removing " + cue); 13603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mActiveCues.remove(cue); 13703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (cue.mRunID == 0) { 13803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar it.remove(); 13903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 14003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } else if (cue.mStartTimeMs == event.first) { 14103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // add new cues 14203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // TRICKY: this will happen in start order 14303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (DEBUG) Log.v(TAG, "Adding " + cue); 14403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (cue.mInnerTimesMs != null) { 14503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cue.onTime(timeMs); 14603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 14703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mActiveCues.add(cue); 14803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } else if (cue.mInnerTimesMs != null) { 14903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // cue is modified 15003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cue.onTime(timeMs); 15103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 15203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 15303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 15403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /* complete any runs */ 15503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar while (mRunsByEndTime.size() > 0 && 15603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mRunsByEndTime.keyAt(0) <= timeMs) { 15703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar removeRunsByEndTimeIndex(0); // removes element 15803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 15903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mLastUpdateTimeMs = timeMs; 16003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 16103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 16203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private void removeRunsByEndTimeIndex(int ix) { 16303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Run run = mRunsByEndTime.valueAt(ix); 16403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar while (run != null) { 16503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Cue cue = run.mFirstCue; 16603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar while (cue != null) { 16703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mCues.remove(cue); 16803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Cue nextCue = cue.mNextInRun; 16903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cue.mNextInRun = null; 17003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cue = nextCue; 17103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 17203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mRunsByID.remove(run.mRunID); 17303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Run nextRun = run.mNextRunAtEndTimeMs; 17403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar run.mPrevRunAtEndTimeMs = null; 17503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar run.mNextRunAtEndTimeMs = null; 17603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar run = nextRun; 17703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 17803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mRunsByEndTime.removeAt(ix); 17903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 18003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 18103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar @Override 18203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar protected void finalize() throws Throwable { 18303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /* remove all cues (untangle all cross-links) */ 18403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar int size = mRunsByEndTime.size(); 18503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar for(int ix = size - 1; ix >= 0; ix--) { 18603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar removeRunsByEndTimeIndex(ix); 18703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 18803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 18903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar super.finalize(); 19003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 19103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 19203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private synchronized void takeTime(long timeMs) { 19303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mLastTimeMs = timeMs; 19403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 19503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 19603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 19703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar protected synchronized void clearActiveCues() { 19803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (DEBUG) Log.v(TAG, "Clearing " + mActiveCues.size() + " active cues"); 19903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mActiveCues.clear(); 20003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mLastUpdateTimeMs = -1; 20103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 20203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 20303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 204d486f9656a6f9d6c056d84fce39f3db8d1614e1dLajos Molnar protected void scheduleTimedEvents() { 20503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /* get times for the next event */ 20603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mTimeProvider != null) { 20703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mNextScheduledTimeMs = mCues.nextTimeAfter(mLastTimeMs); 20803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (DEBUG) Log.d(TAG, "sched @" + mNextScheduledTimeMs + " after " + mLastTimeMs); 20903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mTimeProvider.notifyAt( 21003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mNextScheduledTimeMs >= 0 ? 21103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar (mNextScheduledTimeMs * 1000) : MediaTimeProvider.NO_TIME, 21203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar this); 21303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 21403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 21503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 21603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** 21703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * @hide 21803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar */ 21903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar @Override 22003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void onTimedEvent(long timeUs) { 22103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (DEBUG) Log.d(TAG, "onTimedEvent " + timeUs); 22203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar synchronized (this) { 22303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar long timeMs = timeUs / 1000; 22403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar updateActiveCues(false, timeMs); 22503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar takeTime(timeMs); 22603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 22703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar updateView(mActiveCues); 22803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar scheduleTimedEvents(); 22903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 23003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 23103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** 23203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * @hide 23303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar */ 23403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar @Override 23503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void onSeek(long timeUs) { 23603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (DEBUG) Log.d(TAG, "onSeek " + timeUs); 23703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar synchronized (this) { 23803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar long timeMs = timeUs / 1000; 23903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar updateActiveCues(true, timeMs); 24003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar takeTime(timeMs); 24103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 24203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar updateView(mActiveCues); 24303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar scheduleTimedEvents(); 24403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 24503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 24603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** 24703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar * @hide 24803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar */ 24903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar @Override 25003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void onStop() { 25103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar synchronized (this) { 25203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (DEBUG) Log.d(TAG, "onStop"); 25303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar clearActiveCues(); 25403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mLastTimeMs = -1; 25503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 25603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar updateView(mActiveCues); 25703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mNextScheduledTimeMs = -1; 25803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mTimeProvider.notifyAt(MediaTimeProvider.NO_TIME, this); 25903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 26003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 26103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 26203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar protected MediaTimeProvider mTimeProvider; 26303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 26403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 26503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void show() { 26603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mVisible) { 26703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return; 26803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 26903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 27003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mVisible = true; 271d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette getRenderingWidget().setVisible(true); 27203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mTimeProvider != null) { 27303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mTimeProvider.scheduleUpdate(this); 27403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 27503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 27603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 27703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 27803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void hide() { 27903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (!mVisible) { 28003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return; 28103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 28203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 28303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mTimeProvider != null) { 28403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mTimeProvider.cancelNotifications(this); 28503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 286d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette getRenderingWidget().setVisible(false); 28703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mVisible = false; 28803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 28903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 29003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 29103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar protected synchronized boolean addCue(Cue cue) { 29203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mCues.add(cue); 29303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 29403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (cue.mRunID != 0) { 29503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Run run = mRunsByID.get(cue.mRunID); 29603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (run == null) { 29703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar run = new Run(); 29803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mRunsByID.put(cue.mRunID, run); 29903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar run.mEndTimeMs = cue.mEndTimeMs; 30003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } else if (run.mEndTimeMs < cue.mEndTimeMs) { 30103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar run.mEndTimeMs = cue.mEndTimeMs; 30203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 30303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 30403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // link-up cues in the same run 30503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cue.mNextInRun = run.mFirstCue; 30603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar run.mFirstCue = cue; 30703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 30803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 30903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // if a cue is added that should be visible, need to refresh view 31003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar long nowMs = -1; 31103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mTimeProvider != null) { 31203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar try { 31303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar nowMs = mTimeProvider.getCurrentTimeUs( 31403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar false /* precise */, true /* monotonic */) / 1000; 31503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } catch (IllegalStateException e) { 31603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // handle as it we are not playing 31703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 31803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 31903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 32003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (DEBUG) Log.v(TAG, "mVisible=" + mVisible + ", " + 32103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cue.mStartTimeMs + " <= " + nowMs + ", " + 32203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cue.mEndTimeMs + " >= " + mLastTimeMs); 32303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 32403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mVisible && 32503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cue.mStartTimeMs <= nowMs && 32603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // we don't trust nowMs, so check any cue since last callback 32703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cue.mEndTimeMs >= mLastTimeMs) { 32803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mRunnable != null) { 32903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mHandler.removeCallbacks(mRunnable); 33003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 33103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar final SubtitleTrack track = this; 33203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar final long thenMs = nowMs; 33303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mRunnable = new Runnable() { 33403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar @Override 33503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void run() { 33603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // even with synchronized, it is possible that we are going 33703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // to do multiple updates as the runnable could be already 33803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // running. 33903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar synchronized (track) { 34003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mRunnable = null; 34103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar updateActiveCues(true, thenMs); 34203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar updateView(mActiveCues); 34303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 34403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 34503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar }; 34603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // delay update so we don't update view on every cue. TODO why 10? 34703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mHandler.postDelayed(mRunnable, 10 /* delay */)) { 34803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (DEBUG) Log.v(TAG, "scheduling update"); 34903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } else { 35003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (DEBUG) Log.w(TAG, "failed to schedule subtitle view update"); 35103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 35203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return true; 35303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 35403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 35503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mVisible && 35603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cue.mEndTimeMs >= mLastTimeMs && 35703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar (cue.mStartTimeMs < mNextScheduledTimeMs || 35803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mNextScheduledTimeMs < 0)) { 35903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar scheduleTimedEvents(); 36003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 36103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 36203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return false; 36303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 36403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 36503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 366d486f9656a6f9d6c056d84fce39f3db8d1614e1dLajos Molnar public synchronized void setTimeProvider(MediaTimeProvider timeProvider) { 36703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mTimeProvider == timeProvider) { 36803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return; 36903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 37003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mTimeProvider != null) { 37103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mTimeProvider.cancelNotifications(this); 37203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 37303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mTimeProvider = timeProvider; 37403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mTimeProvider != null) { 37503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mTimeProvider.scheduleUpdate(this); 37603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 37703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 37803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 37903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 38003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 38103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar static class CueList { 38203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private static final String TAG = "CueList"; 38303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // simplistic, inefficient implementation 38403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private SortedMap<Long, Vector<Cue> > mCues; 38503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public boolean DEBUG = false; 38603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 38703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private boolean addEvent(Cue cue, long timeMs) { 38803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Vector<Cue> cues = mCues.get(timeMs); 38903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (cues == null) { 39003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cues = new Vector<Cue>(2); 39103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mCues.put(timeMs, cues); 39203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } else if (cues.contains(cue)) { 39303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // do not duplicate cues 39403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return false; 39503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 39603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 39703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cues.add(cue); 39803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return true; 39903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 40003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 40103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private void removeEvent(Cue cue, long timeMs) { 40203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Vector<Cue> cues = mCues.get(timeMs); 40303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (cues != null) { 40403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar cues.remove(cue); 40503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (cues.size() == 0) { 40603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mCues.remove(timeMs); 40703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 40803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 40903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 41003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 41103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void add(Cue cue) { 41203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // ignore non-positive-duration cues 41303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (cue.mStartTimeMs >= cue.mEndTimeMs) 41403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return; 41503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 41603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (!addEvent(cue, cue.mStartTimeMs)) { 41703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return; 41803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 41903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 42003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar long lastTimeMs = cue.mStartTimeMs; 42103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (cue.mInnerTimesMs != null) { 42203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar for (long timeMs: cue.mInnerTimesMs) { 42303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (timeMs > lastTimeMs && timeMs < cue.mEndTimeMs) { 42403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar addEvent(cue, timeMs); 42503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar lastTimeMs = timeMs; 42603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 42703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 42803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 42903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 43003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar addEvent(cue, cue.mEndTimeMs); 43103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 43203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 43303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void remove(Cue cue) { 43403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar removeEvent(cue, cue.mStartTimeMs); 43503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (cue.mInnerTimesMs != null) { 43603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar for (long timeMs: cue.mInnerTimesMs) { 43703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar removeEvent(cue, timeMs); 43803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 43903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 44003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar removeEvent(cue, cue.mEndTimeMs); 44103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 44203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 44303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public Iterable<Pair<Long, Cue>> entriesBetween( 44403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar final long lastTimeMs, final long timeMs) { 44503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return new Iterable<Pair<Long, Cue> >() { 44603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar @Override 44703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public Iterator<Pair<Long, Cue> > iterator() { 44803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (DEBUG) Log.d(TAG, "slice (" + lastTimeMs + ", " + timeMs + "]="); 44903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar try { 45003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return new EntryIterator( 45103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mCues.subMap(lastTimeMs + 1, timeMs + 1)); 45203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } catch(IllegalArgumentException e) { 45303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return new EntryIterator(null); 45403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 45503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 45603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar }; 45703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 45803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 45903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public long nextTimeAfter(long timeMs) { 46003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar SortedMap<Long, Vector<Cue>> tail = null; 46103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar try { 46203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar tail = mCues.tailMap(timeMs + 1); 46303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (tail != null) { 46403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return tail.firstKey(); 46503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } else { 46603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return -1; 46703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 46803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } catch(IllegalArgumentException e) { 46903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return -1; 47003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } catch(NoSuchElementException e) { 47103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return -1; 47203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 47303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 47403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 47503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar class EntryIterator implements Iterator<Pair<Long, Cue> > { 47603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar @Override 47703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public boolean hasNext() { 47803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return !mDone; 47903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 48003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 48103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar @Override 48203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public Pair<Long, Cue> next() { 48303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mDone) { 48403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar throw new NoSuchElementException(""); 48503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 48603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mLastEntry = new Pair<Long, Cue>( 48703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mCurrentTimeMs, mListIterator.next()); 48803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mLastListIterator = mListIterator; 48903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (!mListIterator.hasNext()) { 49003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar nextKey(); 49103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 49203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return mLastEntry; 49303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 49403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 49503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar @Override 49603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void remove() { 49703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // only allow removing end tags 49803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mLastListIterator == null || 49903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mLastEntry.second.mEndTimeMs != mLastEntry.first) { 50003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar throw new IllegalStateException(""); 50103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 50203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 50303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // remove end-cue 50403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mLastListIterator.remove(); 50503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mLastListIterator = null; 50603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mCues.get(mLastEntry.first).size() == 0) { 50703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mCues.remove(mLastEntry.first); 50803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 50903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 51003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // remove rest of the cues 51103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Cue cue = mLastEntry.second; 51203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar removeEvent(cue, cue.mStartTimeMs); 51303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (cue.mInnerTimesMs != null) { 51403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar for (long timeMs: cue.mInnerTimesMs) { 51503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar removeEvent(cue, timeMs); 51603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 51703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 51803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 51903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 52003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public EntryIterator(SortedMap<Long, Vector<Cue> > cues) { 52103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (DEBUG) Log.v(TAG, cues + ""); 52203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mRemainingCues = cues; 52303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mLastListIterator = null; 52403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar nextKey(); 52503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 52603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 52703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private void nextKey() { 52803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar do { 52903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar try { 53003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mRemainingCues == null) { 53103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar throw new NoSuchElementException(""); 53203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 53303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mCurrentTimeMs = mRemainingCues.firstKey(); 53403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mListIterator = 53503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mRemainingCues.get(mCurrentTimeMs).iterator(); 53603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar try { 53703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mRemainingCues = 53803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mRemainingCues.tailMap(mCurrentTimeMs + 1); 53903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } catch (IllegalArgumentException e) { 54003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mRemainingCues = null; 54103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 54203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mDone = false; 54303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } catch (NoSuchElementException e) { 54403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mDone = true; 54503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mRemainingCues = null; 54603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mListIterator = null; 54703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar return; 54803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 54903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } while (!mListIterator.hasNext()); 55003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 55103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 55203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private long mCurrentTimeMs; 55303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private Iterator<Cue> mListIterator; 55403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private boolean mDone; 55503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private SortedMap<Long, Vector<Cue> > mRemainingCues; 55603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private Iterator<Cue> mLastListIterator; 55703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private Pair<Long,Cue> mLastEntry; 55803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 55903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 56003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar CueList() { 56103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mCues = new TreeMap<Long, Vector<Cue>>(); 56203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 56303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 56403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 56503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 56603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public static class Cue { 56703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public long mStartTimeMs; 56803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public long mEndTimeMs; 56903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public long[] mInnerTimesMs; 57003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public long mRunID; 57103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 57203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 57303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public Cue mNextInRun; 57403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 57503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void onTime(long timeMs) { } 57603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 57703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 57803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide update mRunsByEndTime (with default end time) */ 57903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar protected void finishedRun(long runID) { 58003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (runID != 0 && runID != ~0) { 58103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Run run = mRunsByID.get(runID); 58203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (run != null) { 58303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar run.storeByEndTimeMs(mRunsByEndTime); 58403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 58503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 58603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 58703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 58803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide update mRunsByEndTime with given end time */ 58903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void setRunDiscardTimeMs(long runID, long timeMs) { 59003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (runID != 0 && runID != ~0) { 59103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Run run = mRunsByID.get(runID); 59203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (run != null) { 59303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar run.mEndTimeMs = timeMs; 59403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar run.storeByEndTimeMs(mRunsByEndTime); 59503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 59603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 59703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 59803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 59903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar /** @hide */ 60003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private static class Run { 60103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public Cue mFirstCue; 60203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public Run mNextRunAtEndTimeMs; 60303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public Run mPrevRunAtEndTimeMs; 60403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public long mEndTimeMs = -1; 60503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public long mRunID = 0; 60603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar private long mStoredEndTimeMs = -1; 60703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 60803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void storeByEndTimeMs(LongSparseArray<Run> runsByEndTime) { 60903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // remove old value if any 61003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar int ix = runsByEndTime.indexOfKey(mStoredEndTimeMs); 61103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (ix >= 0) { 61203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mPrevRunAtEndTimeMs == null) { 61303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar assert(this == runsByEndTime.valueAt(ix)); 61403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mNextRunAtEndTimeMs == null) { 61503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar runsByEndTime.removeAt(ix); 61603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } else { 61703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar runsByEndTime.setValueAt(ix, mNextRunAtEndTimeMs); 61803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 61903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 62003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar removeAtEndTimeMs(); 62103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 62203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 62303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar // add new value 62403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mEndTimeMs >= 0) { 62503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mPrevRunAtEndTimeMs = null; 62603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mNextRunAtEndTimeMs = runsByEndTime.get(mEndTimeMs); 62703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mNextRunAtEndTimeMs != null) { 62803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mNextRunAtEndTimeMs.mPrevRunAtEndTimeMs = this; 62903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 63003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar runsByEndTime.put(mEndTimeMs, this); 63103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mStoredEndTimeMs = mEndTimeMs; 63203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 63303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 63403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 63503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar public void removeAtEndTimeMs() { 63603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar Run prev = mPrevRunAtEndTimeMs; 63703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar 63803c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mPrevRunAtEndTimeMs != null) { 63903c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mPrevRunAtEndTimeMs.mNextRunAtEndTimeMs = mNextRunAtEndTimeMs; 64003c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mPrevRunAtEndTimeMs = null; 64103c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 64203c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar if (mNextRunAtEndTimeMs != null) { 64303c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mNextRunAtEndTimeMs.mPrevRunAtEndTimeMs = prev; 64403c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar mNextRunAtEndTimeMs = null; 64503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 64603c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 64703c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar } 648d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 649d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 650d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Interface for rendering subtitles onto a Canvas. 651d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 652d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public interface RenderingWidget { 653d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 654d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Sets the widget's callback, which is used to send updates when the 655d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * rendered data has changed. 656d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 657d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @param callback update callback 658d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 659d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setOnChangedListener(OnChangedListener callback); 660d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 661d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 662d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Sets the widget's size. 663d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 664d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @param width width in pixels 665d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @param height height in pixels 666d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 667d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setSize(int width, int height); 668d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 669d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 670d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Sets whether the widget should draw subtitles. 671d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 672d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @param visible true if subtitles should be drawn, false otherwise 673d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 674d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setVisible(boolean visible); 675d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 676d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 677d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Renders subtitles onto a {@link Canvas}. 678d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 679d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @param c canvas on which to render subtitles 680d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 681d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void draw(Canvas c); 682d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 683d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 684d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Called when the widget is attached to a window. 685d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 686d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onAttachedToWindow(); 687d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 688d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 689d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Called when the widget is detached from a window. 690d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 691d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onDetachedFromWindow(); 692d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 693d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 694d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Callback used to send updates about changes to rendering data. 695d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 696d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public interface OnChangedListener { 697d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** 698d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * Called when the rendering data has changed. 699d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * 700d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @param renderingWidget the widget whose data has changed 701d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette */ 702d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onChanged(RenderingWidget renderingWidget); 703d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 704d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 70503c25794b66b0d01e0e850042713f8009c787dc2Lajos Molnar} 706