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