172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project/*
272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Copyright (C) 2007-2008 Esmertec AG.
372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Copyright (C) 2007-2008 The Android Open Source Project
472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project *
572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * you may not use this file except in compliance with the License.
772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * You may obtain a copy of the License at
872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project *
972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
1072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project *
1172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * See the License for the specific language governing permissions and
1572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * limitations under the License.
1672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project */
1772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
1872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpackage com.android.mms.dom.smil;
1972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
20d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport java.util.ArrayList;
21d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport java.util.Collections;
22d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport java.util.Comparator;
23d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport java.util.HashSet;
24d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chen
2572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport org.w3c.dom.NodeList;
2672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport org.w3c.dom.events.DocumentEvent;
2772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport org.w3c.dom.events.Event;
2872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport org.w3c.dom.events.EventTarget;
2972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport org.w3c.dom.smil.ElementParallelTimeContainer;
3072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport org.w3c.dom.smil.ElementSequentialTimeContainer;
3172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport org.w3c.dom.smil.ElementTime;
3272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport org.w3c.dom.smil.Time;
3372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport org.w3c.dom.smil.TimeList;
3472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
3572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.util.Log;
3672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
3772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project/**
3872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * The SmilPlayer is responsible for playing, stopping, pausing and resuming a SMIL tree.
3972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * <li>It creates a whole timeline before playing.</li>
4072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * <li>The player runs in a different thread which intends not to block the main thread.</li>
4172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project */
4272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpublic class SmilPlayer implements Runnable {
439242286c35743422051d439d7460cd0a1426899cWei Huang    private static final String TAG = "Mms/smil";
4472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final boolean DEBUG = false;
45150c4179995cc0a75f934ef194372f9295957ca2Joe Onorato    private static final boolean LOCAL_LOGV = false;
4672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final int TIMESLICE = 200;
4772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
48b764ab1119f862e033d8b616d9f87ce9a87a87e5Todor Kalaydjiev    private static enum SmilPlayerState {
4972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        INITIALIZED,
5072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        PLAYING,
5172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        PLAYED,
5272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        PAUSED,
5372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        STOPPED,
5472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
5572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
5672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static enum SmilPlayerAction {
5772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NO_ACTIVE_ACTION,
5872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        RELOAD,
5972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        STOP,
6072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        PAUSE,
6172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        START,
62d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        NEXT,
63d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        PREV
6472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
6572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
6672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static final String MEDIA_TIME_UPDATED_EVENT = "mediaTimeUpdated";
6772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
6872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final Comparator<TimelineEntry> sTimelineEntryComparator =
6972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        new Comparator<TimelineEntry>() {
7072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public int compare(TimelineEntry o1, TimelineEntry o2) {
7172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return Double.compare(o1.getOffsetTime(), o2.getOffsetTime());
7272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
7372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    };
7472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
7572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static SmilPlayer sPlayer;
7672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
7772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private long mCurrentTime;
7872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private int mCurrentElement;
7972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private int mCurrentSlide;
8072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private ArrayList<TimelineEntry> mAllEntries;
8172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private ElementTime mRoot;
8272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private Thread mPlayerThread;
8372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private SmilPlayerState mState = SmilPlayerState.INITIALIZED;
8472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private SmilPlayerAction mAction = SmilPlayerAction.NO_ACTIVE_ACTION;
8572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private ArrayList<ElementTime> mActiveElements;
8672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private Event mMediaTimeUpdatedEvent;
8772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
8872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static ArrayList<TimelineEntry> getParTimeline(
8972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            ElementParallelTimeContainer par, double offset, double maxOffset) {
9072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        ArrayList<TimelineEntry> timeline = new ArrayList<TimelineEntry>();
9172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
9272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Set my begin at first
9372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        TimeList myBeginList = par.getBegin();
9472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        /*
9572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         * Begin list only contain 1 begin time which has been resolved.
9672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         * @see com.android.mms.dom.smil.ElementParallelTimeContainerImpl#getBegin()
9772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         */
9872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Time begin = myBeginList.item(0);
9972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        double beginOffset = begin.getResolvedOffset() + offset;
10072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (beginOffset > maxOffset) {
10172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            // This element can't be started.
10272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return timeline;
10372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
10472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        TimelineEntry myBegin = new TimelineEntry(beginOffset, par, TimelineEntry.ACTION_BEGIN);
10572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        timeline.add(myBegin);
10672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
10772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        TimeList myEndList = par.getEnd();
10872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        /*
10972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         * End list only contain 1 end time which has been resolved.
11072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         * @see com.android.mms.dom.smil.ElementParallelTimeContainerImpl#getEnd()
11172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         */
11272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Time end = myEndList.item(0);
11372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        double endOffset = end.getResolvedOffset() + offset;
11472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (endOffset > maxOffset) {
11572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            endOffset = maxOffset;
11672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
11772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        TimelineEntry myEnd = new TimelineEntry(endOffset, par, TimelineEntry.ACTION_END);
11872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
11972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        maxOffset = endOffset;
12072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
12172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NodeList children = par.getTimeChildren();
12272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        for (int i = 0; i < children.getLength(); ++i) {
12372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            ElementTime child = (ElementTime) children.item(i);
12472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            ArrayList<TimelineEntry> childTimeline = getTimeline(child, offset, maxOffset);
12572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            timeline.addAll(childTimeline);
12672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
12772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
12872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Collections.sort(timeline, sTimelineEntryComparator);
12972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
13072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Add end-event to timeline for all active children
13172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NodeList activeChildrenAtEnd = par.getActiveChildrenAt(
13272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                (float) (endOffset - offset) * 1000);
13372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        for (int i = 0; i < activeChildrenAtEnd.getLength(); ++i) {
13472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            timeline.add(new TimelineEntry(endOffset,
13572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    (ElementTime) activeChildrenAtEnd.item(i),
13672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    TimelineEntry.ACTION_END));
13772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
13872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
13972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Set my end at last
14072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        timeline.add(myEnd);
14172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
14272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return timeline;
14372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
14472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
14572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static ArrayList<TimelineEntry> getSeqTimeline(
14672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            ElementSequentialTimeContainer seq, double offset, double maxOffset) {
14772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        ArrayList<TimelineEntry> timeline = new ArrayList<TimelineEntry>();
14872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        double orgOffset = offset;
14972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
15072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Set my begin at first
15172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        TimeList myBeginList = seq.getBegin();
15272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        /*
15372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         * Begin list only contain 1 begin time which has been resolved.
15472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         * @see com.android.mms.dom.smil.ElementSequentialTimeContainerImpl#getBegin()
15572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         */
15672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Time begin = myBeginList.item(0);
15772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        double beginOffset = begin.getResolvedOffset() + offset;
15872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (beginOffset > maxOffset) {
15972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            // This element can't be started.
16072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return timeline;
16172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
16272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        TimelineEntry myBegin = new TimelineEntry(beginOffset, seq, TimelineEntry.ACTION_BEGIN);
16372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        timeline.add(myBegin);
16472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
16572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        TimeList myEndList = seq.getEnd();
16672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        /*
16772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         * End list only contain 1 end time which has been resolved.
16872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         * @see com.android.mms.dom.smil.ElementSequentialTimeContainerImpl#getEnd()
16972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         */
17072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        Time end = myEndList.item(0);
17172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        double endOffset = end.getResolvedOffset() + offset;
17272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (endOffset > maxOffset) {
17372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            endOffset = maxOffset;
17472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
17572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        TimelineEntry myEnd = new TimelineEntry(endOffset, seq, TimelineEntry.ACTION_END);
17672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
17772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        maxOffset = endOffset;
17872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
17972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Get children's timelines
18072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NodeList children = seq.getTimeChildren();
18172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        for (int i = 0; i < children.getLength(); ++i) {
18272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            ElementTime child = (ElementTime) children.item(i);
18372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            ArrayList<TimelineEntry> childTimeline = getTimeline(child, offset, maxOffset);
18472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            timeline.addAll(childTimeline);
18572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
18672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            // Since the child timeline has been sorted, the offset of the last one is the biggest.
18772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            offset = childTimeline.get(childTimeline.size() - 1).getOffsetTime();
18872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
18972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
19072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Add end-event to timeline for all active children
19172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        NodeList activeChildrenAtEnd = seq.getActiveChildrenAt(
19272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                (float) (endOffset - orgOffset));
19372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        for (int i = 0; i < activeChildrenAtEnd.getLength(); ++i) {
19472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            timeline.add(new TimelineEntry(endOffset,
19572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    (ElementTime) activeChildrenAtEnd.item(i),
19672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    TimelineEntry.ACTION_END));
19772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
19872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
19972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Set my end at last
20072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        timeline.add(myEnd);
20172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
20272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return timeline;
20372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
20472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
20572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static ArrayList<TimelineEntry> getTimeline(ElementTime element,
20672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            double offset, double maxOffset) {
20772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (element instanceof ElementParallelTimeContainer) {
20872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return getParTimeline((ElementParallelTimeContainer) element, offset, maxOffset);
20972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else if (element instanceof ElementSequentialTimeContainer) {
21072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return getSeqTimeline((ElementSequentialTimeContainer) element, offset, maxOffset);
21172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else {
21272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            // Not ElementTimeContainer here
21372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            ArrayList<TimelineEntry> timeline = new ArrayList<TimelineEntry>();
21472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
21572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            TimeList beginList = element.getBegin();
21672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            for (int i = 0; i < beginList.getLength(); ++i) {
21772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Time begin = beginList.item(i);
21872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                if (begin.getResolved()) {
21972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    double beginOffset = begin.getResolvedOffset() + offset;
22072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    if (beginOffset <= maxOffset) {
22172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        TimelineEntry entry = new TimelineEntry(beginOffset,
22272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                                element, TimelineEntry.ACTION_BEGIN);
22372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        timeline.add(entry);
22472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    }
22572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                }
22672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
22772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
22872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            TimeList endList = element.getEnd();
22972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            for (int i = 0; i < endList.getLength(); ++i) {
23072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Time end = endList.item(i);
23172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                if (end.getResolved()) {
23272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    double endOffset = end.getResolvedOffset() + offset;
23372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    if (endOffset <= maxOffset) {
23472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        TimelineEntry entry = new TimelineEntry(endOffset,
23572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                                element, TimelineEntry.ACTION_END);
23672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        timeline.add(entry);
23772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    }
23872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                }
23972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
24072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
24172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Collections.sort(timeline, sTimelineEntryComparator);
24272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
24372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return timeline;
24472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
24572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
24672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
24772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private SmilPlayer() {
24872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Private constructor
24972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
25072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
25172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public static SmilPlayer getPlayer() {
25272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (sPlayer == null) {
25372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            sPlayer = new SmilPlayer();
25472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
25572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return sPlayer;
25672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
25772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
25872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized boolean isPlayingState() {
25972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return mState == SmilPlayerState.PLAYING;
26072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
26172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
26272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized boolean isPlayedState() {
26372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return mState == SmilPlayerState.PLAYED;
26472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
26572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
26672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized boolean isPausedState() {
26772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return mState == SmilPlayerState.PAUSED;
26872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
26972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
27072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized boolean isStoppedState() {
27172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return mState == SmilPlayerState.STOPPED;
27272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
27372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
27472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized boolean isPauseAction() {
27572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return mAction == SmilPlayerAction.PAUSE;
27672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
27772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
27872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized boolean isStartAction() {
27972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return mAction == SmilPlayerAction.START;
28072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
28172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
28272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized boolean isStopAction() {
28372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return mAction == SmilPlayerAction.STOP;
28472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
28572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
28672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized boolean isReloadAction() {
28772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return mAction == SmilPlayerAction.RELOAD;
28872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
28972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
290d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    private synchronized boolean isNextAction() {
291d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      return mAction == SmilPlayerAction.NEXT;
292d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    }
293d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
294d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    private synchronized boolean isPrevAction() {
295d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      return mAction == SmilPlayerAction.PREV;
296d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    }
297d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
29872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized void init(ElementTime root) {
29972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mRoot = root;
30072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mAllEntries = getTimeline(mRoot, 0, Long.MAX_VALUE);
30172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mMediaTimeUpdatedEvent = ((DocumentEvent) mRoot).createEvent("Event");
30272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mMediaTimeUpdatedEvent.initEvent(MEDIA_TIME_UPDATED_EVENT, false, false);
30372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mActiveElements = new ArrayList<ElementTime>();
30472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
30572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
30672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized void play() {
30772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (!isPlayingState()) {
30872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mCurrentTime = 0;
30972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mCurrentElement = 0;
31072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mCurrentSlide = 0;
311ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev            mPlayerThread = new Thread(this, "SmilPlayer thread");
31272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mState = SmilPlayerState.PLAYING;
31372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mPlayerThread.start();
31472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else {
31572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Log.w(TAG, "Error State: Playback is playing!");
31672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
31772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
31872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
31972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized void pause() {
32072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isPlayingState()) {
32172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mAction = SmilPlayerAction.PAUSE;
32272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            notifyAll();
32372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else {
32472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Log.w(TAG, "Error State: Playback is not playing!");
32572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
32672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
32772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
32872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized void start() {
32972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isPausedState()) {
33072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            resumeActiveElements();
33172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mAction = SmilPlayerAction.START;
33272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            notifyAll();
33372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else if (isPlayedState()) {
33472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            play();
33572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else {
33672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Log.w(TAG, "Error State: Playback can not be started!");
33772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
33872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
33972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
34072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized void stop() {
34172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isPlayingState() || isPausedState()) {
34272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mAction = SmilPlayerAction.STOP;
34372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            notifyAll();
34472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else if (isPlayedState()) {
34572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            actionStop();
34672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
34772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
34872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
34972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized void stopWhenReload() {
35072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        endActiveElements();
35172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
35272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
35372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized void reload() {
35472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isPlayingState() || isPausedState()) {
35572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mAction = SmilPlayerAction.RELOAD;
35672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            notifyAll();
35772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } else if (isPlayedState()) {
35872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            actionReload();
35972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
36072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
36172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
362d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    public synchronized void next() {
363d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      if (isPlayingState() || isPausedState()) {
364d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        mAction = SmilPlayerAction.NEXT;
365d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        notifyAll();
366d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      }
367d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    }
368d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
369d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    public synchronized void prev() {
370d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      if (isPlayingState() || isPausedState()) {
371d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        mAction = SmilPlayerAction.PREV;
372d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        notifyAll();
373d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      }
374d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    }
375d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
37672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized boolean isBeginOfSlide(TimelineEntry entry) {
37772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return (TimelineEntry.ACTION_BEGIN == entry.getAction())
37872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    && (entry.getElement() instanceof SmilParElementImpl);
37972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
38072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
38172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized void reloadActiveSlide() {
38272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mActiveElements.clear();
38372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        beginSmilDocument();
38472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
38572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        for (int i = mCurrentSlide; i < mCurrentElement; i++) {
38672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            TimelineEntry entry = mAllEntries.get(i);
38772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            actionEntry(entry);
38872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
38972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        seekActiveMedia();
39072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
39172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
39272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized void beginSmilDocument() {
39372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        TimelineEntry entry = mAllEntries.get(0);
39472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        actionEntry(entry);
39572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
39672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
39772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized double getOffsetTime(ElementTime element) {
39872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        for (int i = mCurrentSlide; i < mCurrentElement; i++) {
39972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            TimelineEntry entry = mAllEntries.get(i);
40072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (element.equals(entry.getElement())) {
40172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                return entry.getOffsetTime() * 1000;  // in ms
40272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
40372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
40472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return -1;
40572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
40672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
40772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized void seekActiveMedia() {
40872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        for (int i = mActiveElements.size() - 1; i >= 0; i--) {
40972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            ElementTime element = mActiveElements.get(i);
41072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (element instanceof SmilParElementImpl) {
41172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                return;
41272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
41372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            double offset = getOffsetTime(element);
41472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if ((offset >= 0) && (offset <= mCurrentTime)) {
41572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                if (LOCAL_LOGV) {
41672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    Log.v(TAG, "[SEEK]  " + " at " + mCurrentTime
41772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            + " " + element);
41872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                }
41972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                element.seekElement( (float) (mCurrentTime - offset) );
42072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
42172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
42272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
42372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
42472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized void waitForEntry(long interval)
42572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            throws InterruptedException {
42672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (LOCAL_LOGV) {
42772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Log.v(TAG, "Waiting for " + interval + "ms.");
42872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
42972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
43072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        long overhead = 0;
43172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
43272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        while (interval > 0) {
43372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long startAt = System.currentTimeMillis();
43472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long sleep = Math.min(interval, TIMESLICE);
43572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (overhead < sleep) {
43672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                wait(sleep - overhead);
43772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                mCurrentTime += sleep;
43872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            } else {
43972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                sleep = 0;
44072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                mCurrentTime += overhead;
44172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
44272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
443d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            if (isStopAction() || isReloadAction() || isPauseAction() || isNextAction() ||
444d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                isPrevAction()) {
44572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                return;
44672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
44772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
44872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            ((EventTarget) mRoot).dispatchEvent(mMediaTimeUpdatedEvent);
44972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
45072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            interval -= TIMESLICE;
45172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            overhead = System.currentTimeMillis() - startAt - sleep;
45272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
45372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
45472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
45572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized int getDuration() {
45672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         if ((mAllEntries != null) && !mAllEntries.isEmpty()) {
45772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project             return (int) mAllEntries.get(mAllEntries.size() - 1).mOffsetTime * 1000;
45872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         }
45972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project         return 0;
46072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
46172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
46272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public synchronized int getCurrentPosition() {
46372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        return (int) mCurrentTime;
46472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
46572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
46672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized void endActiveElements() {
46772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        for (int i = mActiveElements.size() - 1; i >= 0; i--) {
46872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            ElementTime element = mActiveElements.get(i);
46972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (LOCAL_LOGV) {
47072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Log.v(TAG, "[STOP]  " + " at " + mCurrentTime
47172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        + " " + element);
47272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
47372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            element.endElement();
47472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
47572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
47672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
47772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized void pauseActiveElements() {
47872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        for (int i = mActiveElements.size() - 1; i >= 0; i--) {
47972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            ElementTime element = mActiveElements.get(i);
48072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (LOCAL_LOGV) {
48172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Log.v(TAG, "[PAUSE]  " + " at " + mCurrentTime
48272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        + " " + element);
48372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
48472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            element.pauseElement();
48572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
48672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
48772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
48872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized void resumeActiveElements() {
48972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int size = mActiveElements.size();
49072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        for (int i = 0; i < size; i++) {
49172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            ElementTime element = mActiveElements.get(i);
49272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (LOCAL_LOGV) {
49372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                Log.v(TAG, "[RESUME]  " + " at " + mCurrentTime
49472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        + " " + element);
49572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
49672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            element.resumeElement();
49772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
49872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
49972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
50072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized void waitForWakeUp() {
50172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        try {
502d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            while ( !(isStartAction() || isStopAction() || isReloadAction() ||
503d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                    isNextAction() || isPrevAction()) ) {
50472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                wait(TIMESLICE);
50572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
50672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (isStartAction()) {
50772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                mAction = SmilPlayerAction.NO_ACTIVE_ACTION;
50872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                mState = SmilPlayerState.PLAYING;
50972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
51072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        } catch (InterruptedException e) {
51172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            Log.e(TAG, "Unexpected InterruptedException.", e);
51272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
51372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
51472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
51572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized void actionEntry(TimelineEntry entry) {
51672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        switch (entry.getAction()) {
51772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            case TimelineEntry.ACTION_BEGIN:
51872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                if (LOCAL_LOGV) {
51972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    Log.v(TAG, "[START] " + " at " + mCurrentTime + " "
52072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            + entry.getElement());
52172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                }
52272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                entry.getElement().beginElement();
52372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                mActiveElements.add(entry.getElement());
52472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                break;
52572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            case TimelineEntry.ACTION_END:
52672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                if (LOCAL_LOGV) {
52772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    Log.v(TAG, "[STOP]  " + " at " + mCurrentTime + " "
52872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            + entry.getElement());
52972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                }
53072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                entry.getElement().endElement();
53172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                mActiveElements.remove(entry.getElement());
53272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                break;
53372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            default:
53472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                break;
53572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
53672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
53772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
53872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized TimelineEntry reloadCurrentEntry() {
5396a7ba7cf4d775dbb29f3cafbee67d823149da5f1Naveen Kalla        // Check if the position is less than size of all entries
5406a7ba7cf4d775dbb29f3cafbee67d823149da5f1Naveen Kalla        if (mCurrentElement < mAllEntries.size()) {
5416a7ba7cf4d775dbb29f3cafbee67d823149da5f1Naveen Kalla            return mAllEntries.get(mCurrentElement);
5426a7ba7cf4d775dbb29f3cafbee67d823149da5f1Naveen Kalla        } else {
5436a7ba7cf4d775dbb29f3cafbee67d823149da5f1Naveen Kalla            return null;
5446a7ba7cf4d775dbb29f3cafbee67d823149da5f1Naveen Kalla        }
54572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
54672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
547d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    private void stopCurrentSlide() {
548d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        HashSet<TimelineEntry> skippedEntries = new HashSet<TimelineEntry>();
549d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        int totalEntries = mAllEntries.size();
550d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        for (int i = mCurrentElement; i < totalEntries; i++) {
551d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            // Stop any started entries, and skip the not started entries until
552d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            // meeting the end of slide
553d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            TimelineEntry entry = mAllEntries.get(i);
554d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            int action = entry.getAction();
555d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            if (entry.getElement() instanceof SmilParElementImpl &&
556d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                    action == TimelineEntry.ACTION_END) {
557d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                actionEntry(entry);
558d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                mCurrentElement = i;
559d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                break;
560d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            } else if (action == TimelineEntry.ACTION_END && !skippedEntries.contains(entry)) {
561d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                    actionEntry(entry);
562d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            } else if (action == TimelineEntry.ACTION_BEGIN) {
563d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                skippedEntries.add(entry);
564d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            }
565d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        }
566d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    }
567d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
568d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    private TimelineEntry loadNextSlide() {
569d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      TimelineEntry entry;
570d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      int totalEntries = mAllEntries.size();
571d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      for (int i = mCurrentElement; i < totalEntries; i++) {
572d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao          entry = mAllEntries.get(i);
573d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao          if (isBeginOfSlide(entry)) {
574d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao              mCurrentElement = i;
575d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao              mCurrentSlide = i;
576d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao              mCurrentTime = (long)(entry.getOffsetTime() * 1000);
577d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao              return entry;
578d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao          }
579d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      }
580d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      // No slide, finish play back
581d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      mCurrentElement++;
582d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      entry = null;
583d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      if (mCurrentElement < totalEntries) {
584d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao          entry = mAllEntries.get(mCurrentElement);
585d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao          mCurrentTime = (long)(entry.getOffsetTime() * 1000);
586d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      }
587d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      return entry;
588d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    }
589d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
590d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    private TimelineEntry loadPrevSlide() {
591d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      int skippedSlides = 1;
592d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      int latestBeginEntryIndex = -1;
593d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      for (int i = mCurrentSlide; i >= 0; i--) {
594d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        TimelineEntry entry = mAllEntries.get(i);
595d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        if (isBeginOfSlide(entry)) {
596d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            latestBeginEntryIndex = i;
597d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao          if (0 == skippedSlides-- ) {
598d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            mCurrentElement = i;
599d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            mCurrentSlide = i;
600d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            mCurrentTime = (long)(entry.getOffsetTime() * 1000);
601d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            return entry;
602d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao          }
603d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        }
604d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      }
605d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      if (latestBeginEntryIndex != -1) {
606d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao          mCurrentElement = latestBeginEntryIndex;
607d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao          mCurrentSlide = latestBeginEntryIndex;
608d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao          return mAllEntries.get(mCurrentElement);
609d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      }
610d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao      return null;
611d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    }
612d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
613d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    private synchronized TimelineEntry actionNext() {
614d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        stopCurrentSlide();
615d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        return loadNextSlide();
616d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao   }
617d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
618d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    private synchronized TimelineEntry actionPrev() {
619d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        stopCurrentSlide();
620d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        return loadPrevSlide();
621d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    }
622d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
62372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized void actionPause() {
62472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        pauseActiveElements();
62572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mState = SmilPlayerState.PAUSED;
62672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mAction = SmilPlayerAction.NO_ACTIVE_ACTION;
62772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
62872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
62972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized void actionStop() {
63072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        endActiveElements();
63172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mCurrentTime = 0;
63272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mCurrentElement = 0;
63372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mCurrentSlide = 0;
63472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mState = SmilPlayerState.STOPPED;
63572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mAction = SmilPlayerAction.NO_ACTIVE_ACTION;
63672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
63772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
63872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private synchronized void actionReload() {
63972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        reloadActiveSlide();
64072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mAction = SmilPlayerAction.NO_ACTIVE_ACTION;
64172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
64272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
64372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    public void run() {
64472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        if (isStoppedState()) {
64572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return;
64672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
647d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        if (LOCAL_LOGV) {
648d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            dumpAllEntries();
649d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        }
65072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        // Play the Element by following the timeline
65172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        int size = mAllEntries.size();
65272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        for (mCurrentElement = 0; mCurrentElement < size; mCurrentElement++) {
65372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            TimelineEntry entry = mAllEntries.get(mCurrentElement);
65472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            if (isBeginOfSlide(entry)) {
65572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                mCurrentSlide = mCurrentElement;
65672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
65772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            long offset = (long) (entry.getOffsetTime() * 1000); // in ms.
65872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            while (offset > mCurrentTime) {
65972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                try {
66072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    waitForEntry(offset - mCurrentTime);
66172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                } catch (InterruptedException e) {
66272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    Log.e(TAG, "Unexpected InterruptedException.", e);
66372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                }
66472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
665d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                while (isPauseAction() || isStopAction() || isReloadAction() || isNextAction() ||
666d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                    isPrevAction()) {
66772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    if (isPauseAction()) {
66872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        actionPause();
66972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        waitForWakeUp();
67072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    }
67172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
67272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    if (isStopAction()) {
67372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        actionStop();
67472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        return;
67572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    }
67672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
67772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    if (isReloadAction()) {
67872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        actionReload();
67972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        entry = reloadCurrentEntry();
6806a7ba7cf4d775dbb29f3cafbee67d823149da5f1Naveen Kalla                        if (entry == null)
6816a7ba7cf4d775dbb29f3cafbee67d823149da5f1Naveen Kalla                            return;
68272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        if (isPausedState()) {
68372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                            mAction = SmilPlayerAction.PAUSE;
68472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                        }
68572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                    }
686d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
687d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                    if (isNextAction()) {
688d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        TimelineEntry nextEntry = actionNext();
689d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        if (nextEntry != null) {
690d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                            entry = nextEntry;
691d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        }
692d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        if (mState == SmilPlayerState.PAUSED) {
693d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                            mAction = SmilPlayerAction.PAUSE;
694d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                            actionEntry(entry);
695d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        } else {
696d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                            mAction = SmilPlayerAction.NO_ACTIVE_ACTION;
697d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        }
698d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        offset = mCurrentTime;
699d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                    }
700d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
701d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                    if (isPrevAction()) {
702d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        TimelineEntry prevEntry = actionPrev();
703d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        if (prevEntry != null) {
704d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                            entry = prevEntry;
705d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        }
706d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        if (mState == SmilPlayerState.PAUSED) {
707d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                            mAction = SmilPlayerAction.PAUSE;
708d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                            actionEntry(entry);
709d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        } else {
710d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                            mAction = SmilPlayerAction.NO_ACTIVE_ACTION;
711d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        }
712d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                        offset = mCurrentTime;
713d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                    }
71472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project                }
71572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            }
71672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mCurrentTime = offset;
71772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            actionEntry(entry);
71872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
71972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
72072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        mState = SmilPlayerState.PLAYED;
72172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
72272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
72372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    private static final class TimelineEntry {
72472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        final static int ACTION_BEGIN = 0;
72572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        final static int ACTION_END   = 1;
72672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
72772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        private final double mOffsetTime;
72872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        private final ElementTime mElement;
72972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        private final int mAction;
73072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
73172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public TimelineEntry(double offsetTime, ElementTime element, int action) {
73272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mOffsetTime = offsetTime;
73372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mElement = element;
73472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            mAction  = action;
73572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
73672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
73772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public double getOffsetTime() {
73872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return mOffsetTime;
73972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
74072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
74172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public ElementTime getElement() {
74272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return mElement;
74372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
74472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project
74572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        public int getAction() {
74672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project            return mAction;
74772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project        }
748d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
749d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        public String toString() {
750d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            return "Type = " + mElement + " offset = " + getOffsetTime() + " action = " + getAction();
751d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        }
752d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    }
753d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao
754d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao    private void dumpAllEntries() {
755d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        if (LOCAL_LOGV) {
756d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            for (TimelineEntry entry : mAllEntries) {
757d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao                Log.v(TAG, "[Entry] "+ entry);
758d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao            }
759d7a1ec4c8a007f707cc3115ed6e558f839f875eaBai Tao        }
76072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project    }
76172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project}
762