/*
* Copyright (C) 2007-2008 Esmertec AG.
* Copyright (C) 2007-2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.mms.dom.smil;
import java.util.ArrayList;
import org.w3c.dom.DOMException;
import org.w3c.dom.smil.ElementTime;
import org.w3c.dom.smil.SMILElement;
import org.w3c.dom.smil.Time;
import org.w3c.dom.smil.TimeList;
import android.util.Log;
public abstract class ElementTimeImpl implements ElementTime {
private static final String TAG = "ElementTimeImpl";
private static final String FILL_REMOVE_ATTRIBUTE = "remove";
private static final String FILL_FREEZE_ATTRIBUTE = "freeze";
private static final String FILL_HOLD_ATTRIBUTE = "hold";
private static final String FILL_TRANSITION_ATTRIBUTE = "transition";
private static final String FILL_AUTO_ATTRIBUTE = "auto";
private static final String FILL_ATTRIBUTE_NAME = "fill";
private static final String FILLDEFAULT_ATTRIBUTE_NAME = "fillDefault";
final SMILElement mSmilElement;
/*
* Internal Interface
*/
ElementTimeImpl(SMILElement element) {
mSmilElement = element;
}
// Default implementation. Override if required.
int getBeginConstraints() {
return TimeImpl.ALLOW_ALL;
}
// Default implementation. Override if required
int getEndConstraints() {
return TimeImpl.ALLOW_ALL;
}
/**
* To get the parent node on the ElementTime tree. It is in opposition to getTimeChildren.
* @return the parent ElementTime. Returns <code>null</code> if there is no parent.
*/
abstract ElementTime getParentElementTime();
/*
* ElementTime Interface
*/
public TimeList getBegin() {
String[] beginTimeStringList = mSmilElement.getAttribute("begin").split(";");
// TODO: Check other constraints on parsed values, e.g., "single, non-negative offset values
ArrayList<Time> beginTimeList = new ArrayList<Time>();
// Initialize Time instances and add them to Vector
for (int i = 0; i < beginTimeStringList.length; i++) {
try {
beginTimeList.add(new TimeImpl(beginTimeStringList[i], getBeginConstraints()));
} catch (IllegalArgumentException e) {
// Ignore badly formatted times
}
}
if (beginTimeList.size() == 0) {
/*
* What is the right default value?
*
* In MMS SMIL, this method may be called either on an instance of:
*
* 1 - ElementSequentialTimeContainer (The SMILDocument)
* 2 - ElementParallelTimeContainer (A Time-Child of the SMILDocument, which is a seq)
* 3 - ElementTime (A SMILMediaElement).
*
* 1 - In the first case, the default start time is obviously 0.
* 2 - In the second case, the specifications mentions that
* "For children of a sequence, the only legal value for begin is
* a (single) non-negative offset value. The default begin value is 0."
* 3 - In the third case, the specification mentions that
* "The default value of begin for children of a par is 0."
*
* In short, if no value is specified, the default is always 0.
*/
beginTimeList.add(new TimeImpl("0", TimeImpl.ALLOW_ALL));
}
return new TimeListImpl(beginTimeList);
}
public float getDur() {
float dur = 0;
try {
String durString = mSmilElement.getAttribute("dur");
if (durString != null) {
dur = TimeImpl.parseClockValue(durString) / 1000f;
}
} catch (IllegalArgumentException e) {
// Do nothing and return the minimum value
}
return dur;
}
public TimeList getEnd() {
ArrayList<Time> endTimeList = new ArrayList<Time>();
String[] endTimeStringList = mSmilElement.getAttribute("end").split(";");
int len = endTimeStringList.length;
if (!((len == 1) && (endTimeStringList[0].length() == 0))) { // Ensure the end field is set.
// Initialize Time instances and add them to Vector
for (int i = 0; i < len; i++) {
try {
endTimeList.add(new TimeImpl(endTimeStringList[i],
getEndConstraints()));
} catch (IllegalArgumentException e) {
// Ignore badly formatted times
Log.e(TAG, "Malformed time value.", e);
}
}
}
// "end" time is not specified
if (endTimeList.size() == 0) {
// Get duration
float duration = getDur();
if (duration < 0) {
endTimeList.add(new TimeImpl("indefinite", getEndConstraints()));
} else {
// Get begin
TimeList begin = getBegin();
for (int i = 0; i < begin.getLength(); i++) {
endTimeList.add(new TimeImpl(
// end = begin + dur
begin.item(i).getResolvedOffset() + duration + "s",
getEndConstraints()));
}
}
}
return new TimeListImpl(endTimeList);
}
private boolean beginAndEndAreZero() {
TimeList begin = getBegin();
TimeList end = getEnd();
if (begin.getLength() == 1 && end.getLength() == 1) {
Time beginTime = begin.item(0);
Time endTime = end.item(0);
return beginTime.getOffset() == 0. && endTime.getOffset() == 0.;
}
return false;
}
public short getFill() {
String fill = mSmilElement.getAttribute(FILL_ATTRIBUTE_NAME);
if (fill.equalsIgnoreCase(FILL_FREEZE_ATTRIBUTE)) {
return FILL_FREEZE;
} else if (fill.equalsIgnoreCase(FILL_REMOVE_ATTRIBUTE)) {
return FILL_REMOVE;
} else if (fill.equalsIgnoreCase(FILL_HOLD_ATTRIBUTE)) {
// FIXME handle it as freeze for now
return FILL_FREEZE;
} else if (fill.equalsIgnoreCase(FILL_TRANSITION_ATTRIBUTE)) {
// FIXME handle it as freeze for now
return FILL_FREEZE;
} else if (!fill.equalsIgnoreCase(FILL_AUTO_ATTRIBUTE)) {
/*
* fill = default
* The fill behavior for the element is determined by the value of the fillDefault
* attribute. This is the default value.
*/
short fillDefault = getFillDefault();
if (fillDefault != FILL_AUTO) {
return fillDefault;
}
}
/*
* fill = auto
* The fill behavior for this element depends on whether the element specifies any of
* the attributes that define the simple or active duration:
* - If none of the attributes dur, end, repeatCount or repeatDur are specified on
* the element, then the element will have a fill behavior identical to that if it were
* specified as "freeze".
* - Otherwise, the element will have a fill behavior identical to that if it were
* specified as "remove".
*/
if (((mSmilElement.getAttribute("dur").length() == 0) &&
(mSmilElement.getAttribute("end").length() == 0) &&
(mSmilElement.getAttribute("repeatCount").length() == 0) &&
(mSmilElement.getAttribute("repeatDur").length() == 0)) ||
beginAndEndAreZero()) {
return FILL_FREEZE;
} else {
return FILL_REMOVE;
}
}
public short getFillDefault() {
String fillDefault = mSmilElement.getAttribute(FILLDEFAULT_ATTRIBUTE_NAME);
if (fillDefault.equalsIgnoreCase(FILL_REMOVE_ATTRIBUTE)) {
return FILL_REMOVE;
} else if (fillDefault.equalsIgnoreCase(FILL_FREEZE_ATTRIBUTE)) {
return FILL_FREEZE;
} else if (fillDefault.equalsIgnoreCase(FILL_AUTO_ATTRIBUTE)) {
return FILL_AUTO;
} else if (fillDefault.equalsIgnoreCase(FILL_HOLD_ATTRIBUTE)) {
// FIXME handle it as freeze for now
return FILL_FREEZE;
} else if (fillDefault.equalsIgnoreCase(FILL_TRANSITION_ATTRIBUTE)) {
// FIXME handle it as freeze for now
return FILL_FREEZE;
} else {
/*
* fillDefault = inherit
* Specifies that the value of this attribute (and of the fill behavior) are
* inherited from the fillDefault value of the parent element.
* This is the default value.
*/
ElementTime parent = getParentElementTime();
if (parent == null) {
/*
* fillDefault = auto
* If there is no parent element, the value is "auto".
*/
return FILL_AUTO;
} else {
return ((ElementTimeImpl) parent).getFillDefault();
}
}
}
public float getRepeatCount() {
String repeatCount = mSmilElement.getAttribute("repeatCount");
try {
float value = Float.parseFloat(repeatCount);
if (value > 0) {
return value;
} else {
return 0; // default
}
} catch (NumberFormatException e) {
return 0; // default
}
}
public float getRepeatDur() {
try {
float repeatDur =
TimeImpl.parseClockValue(mSmilElement.getAttribute("repeatDur"));
if (repeatDur > 0) {
return repeatDur;
} else {
return 0; // default
}
} catch (IllegalArgumentException e) {
return 0; // default
}
}
public short getRestart() {
String restart = mSmilElement.getAttribute("restart");
if (restart.equalsIgnoreCase("never")) {
return RESTART_NEVER;
} else if (restart.equalsIgnoreCase("whenNotActive")) {
return RESTART_WHEN_NOT_ACTIVE;
} else {
return RESTART_ALWAYS; // default
}
}
public void setBegin(TimeList begin) throws DOMException {
// TODO Implement this
mSmilElement.setAttribute("begin", "indefinite");
}
public void setDur(float dur) throws DOMException {
// In SMIL 3.0, the dur could be a timecount-value which may contain fractions.
// However, in MMS 1.3, the dur SHALL be expressed in integer milliseconds.
mSmilElement.setAttribute("dur", Integer.toString((int)(dur * 1000)) + "ms");
}
public void setEnd(TimeList end) throws DOMException {
// TODO Implement this
mSmilElement.setAttribute("end", "indefinite");
}
public void setFill(short fill) throws DOMException {
if (fill == FILL_FREEZE) {
mSmilElement.setAttribute(FILL_ATTRIBUTE_NAME, FILL_FREEZE_ATTRIBUTE);
} else {
mSmilElement.setAttribute(FILL_ATTRIBUTE_NAME, FILL_REMOVE_ATTRIBUTE); // default
}
}
public void setFillDefault(short fillDefault) throws DOMException {
if (fillDefault == FILL_FREEZE) {
mSmilElement.setAttribute(FILLDEFAULT_ATTRIBUTE_NAME, FILL_FREEZE_ATTRIBUTE);
} else {
mSmilElement.setAttribute(FILLDEFAULT_ATTRIBUTE_NAME, FILL_REMOVE_ATTRIBUTE);
}
}
public void setRepeatCount(float repeatCount) throws DOMException {
String repeatCountString = "indefinite";
if (repeatCount > 0) {
repeatCountString = Float.toString(repeatCount);
}
mSmilElement.setAttribute("repeatCount", repeatCountString);
}
public void setRepeatDur(float repeatDur) throws DOMException {
String repeatDurString = "indefinite";
if (repeatDur > 0) {
repeatDurString = Float.toString(repeatDur) + "ms";
}
mSmilElement.setAttribute("repeatDur", repeatDurString);
}
public void setRestart(short restart) throws DOMException {
if (restart == RESTART_NEVER) {
mSmilElement.setAttribute("restart", "never");
} else if (restart == RESTART_WHEN_NOT_ACTIVE) {
mSmilElement.setAttribute("restart", "whenNotActive");
} else {
mSmilElement.setAttribute("restart", "always");
}
}
}