Home | History | Annotate | Download | only in smil
      1 /*
      2  * Copyright (C) 2007-2008 Esmertec AG.
      3  * Copyright (C) 2007-2008 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package com.android.mms.dom.smil;
     19 
     20 import com.android.mms.LogTag;
     21 
     22 import java.util.ArrayList;
     23 
     24 import org.w3c.dom.DOMException;
     25 import org.w3c.dom.smil.ElementTime;
     26 import org.w3c.dom.smil.SMILElement;
     27 import org.w3c.dom.smil.Time;
     28 import org.w3c.dom.smil.TimeList;
     29 
     30 import android.util.Log;
     31 
     32 public abstract class ElementTimeImpl implements ElementTime {
     33     private static final String TAG = LogTag.TAG;
     34 
     35     private static final String FILL_REMOVE_ATTRIBUTE = "remove";
     36     private static final String FILL_FREEZE_ATTRIBUTE = "freeze";
     37     private static final String FILL_HOLD_ATTRIBUTE = "hold";
     38     private static final String FILL_TRANSITION_ATTRIBUTE = "transition";
     39     private static final String FILL_AUTO_ATTRIBUTE   = "auto";
     40     private static final String FILL_ATTRIBUTE_NAME   = "fill";
     41     private static final String FILLDEFAULT_ATTRIBUTE_NAME   = "fillDefault";
     42 
     43     final SMILElement mSmilElement;
     44 
     45     /*
     46      * Internal Interface
     47      */
     48     ElementTimeImpl(SMILElement element) {
     49         mSmilElement = element;
     50     }
     51 
     52     // Default implementation. Override if required.
     53     int getBeginConstraints() {
     54         return TimeImpl.ALLOW_ALL;
     55     }
     56 
     57     // Default implementation. Override if required
     58     int getEndConstraints() {
     59         return TimeImpl.ALLOW_ALL;
     60     }
     61 
     62     /**
     63      * To get the parent node on the ElementTime tree. It is in opposition to getTimeChildren.
     64      * @return the parent ElementTime. Returns <code>null</code> if there is no parent.
     65      */
     66     abstract ElementTime getParentElementTime();
     67 
     68     /*
     69      * ElementTime Interface
     70      */
     71 
     72     public TimeList getBegin() {
     73         String[] beginTimeStringList = mSmilElement.getAttribute("begin").split(";");
     74 
     75         // TODO: Check other constraints on parsed values, e.g., "single, non-negative offset values
     76         ArrayList<Time> beginTimeList = new ArrayList<Time>();
     77         // Initialize Time instances and add them to Vector
     78         for (int i = 0; i < beginTimeStringList.length; i++) {
     79             try {
     80                 beginTimeList.add(new TimeImpl(beginTimeStringList[i], getBeginConstraints()));
     81             } catch (IllegalArgumentException e) {
     82                 // Ignore badly formatted times
     83             }
     84         }
     85         if (beginTimeList.size() == 0) {
     86             /*
     87              * What is the right default value?
     88              *
     89              * In MMS SMIL, this method may be called either on an instance of:
     90              *
     91              * 1 - ElementSequentialTimeContainer (The SMILDocument)
     92              * 2 - ElementParallelTimeContainer (A Time-Child of the SMILDocument, which is a seq)
     93              * 3 - ElementTime (A SMILMediaElement).
     94              *
     95              * 1 - In the first case, the default start time is obviously 0.
     96              * 2 - In the second case, the specifications mentions that
     97              *      "For children of a sequence, the only legal value for begin is
     98              *      a (single) non-negative offset value. The default begin value is 0."
     99              * 3 - In the third case, the specification mentions that
    100              *      "The default value of begin for children of a par is 0."
    101              *
    102              * In short, if no value is specified, the default is always 0.
    103              */
    104 
    105             beginTimeList.add(new TimeImpl("0", TimeImpl.ALLOW_ALL));
    106         }
    107         return new TimeListImpl(beginTimeList);
    108     }
    109 
    110     public float getDur() {
    111         float dur = 0;
    112         try {
    113             String durString = mSmilElement.getAttribute("dur");
    114             if (durString != null) {
    115                 dur = TimeImpl.parseClockValue(durString) / 1000f;
    116             }
    117         } catch (IllegalArgumentException e) {
    118             // Do nothing and return the minimum value
    119         }
    120 
    121         return dur;
    122     }
    123 
    124     public TimeList getEnd() {
    125         ArrayList<Time> endTimeList = new ArrayList<Time>();
    126 
    127         String[] endTimeStringList = mSmilElement.getAttribute("end").split(";");
    128         int len = endTimeStringList.length;
    129         if (!((len == 1) && (endTimeStringList[0].length() == 0))) {  // Ensure the end field is set.
    130             // Initialize Time instances and add them to Vector
    131             for (int i = 0; i < len; i++) {
    132                 try {
    133                     endTimeList.add(new TimeImpl(endTimeStringList[i],
    134                             getEndConstraints()));
    135                 } catch (IllegalArgumentException e) {
    136                     // Ignore badly formatted times
    137                     Log.e(TAG, "Malformed time value.", e);
    138                 }
    139             }
    140         }
    141 
    142         // "end" time is not specified
    143         if (endTimeList.size() == 0) {
    144             // Get duration
    145             float duration = getDur();
    146 
    147             if (duration < 0) {
    148                 endTimeList.add(new TimeImpl("indefinite", getEndConstraints()));
    149             } else {
    150                 // Get begin
    151                 TimeList begin = getBegin();
    152                 for (int i = 0; i < begin.getLength(); i++) {
    153                     endTimeList.add(new TimeImpl(
    154                             // end = begin + dur
    155                             begin.item(i).getResolvedOffset() + duration + "s",
    156                             getEndConstraints()));
    157                 }
    158             }
    159         }
    160 
    161         return new TimeListImpl(endTimeList);
    162     }
    163 
    164     private boolean beginAndEndAreZero() {
    165         TimeList begin = getBegin();
    166         TimeList end = getEnd();
    167         if (begin.getLength() == 1 && end.getLength() == 1) {
    168             Time beginTime = begin.item(0);
    169             Time endTime = end.item(0);
    170             return beginTime.getOffset() == 0. && endTime.getOffset() == 0.;
    171         }
    172         return false;
    173     }
    174 
    175     public short getFill() {
    176         String fill = mSmilElement.getAttribute(FILL_ATTRIBUTE_NAME);
    177         if (fill.equalsIgnoreCase(FILL_FREEZE_ATTRIBUTE)) {
    178             return FILL_FREEZE;
    179         } else if (fill.equalsIgnoreCase(FILL_REMOVE_ATTRIBUTE)) {
    180             return FILL_REMOVE;
    181         } else if (fill.equalsIgnoreCase(FILL_HOLD_ATTRIBUTE)) {
    182             // FIXME handle it as freeze for now
    183             return FILL_FREEZE;
    184         } else if (fill.equalsIgnoreCase(FILL_TRANSITION_ATTRIBUTE)) {
    185             // FIXME handle it as freeze for now
    186             return FILL_FREEZE;
    187         } else if (!fill.equalsIgnoreCase(FILL_AUTO_ATTRIBUTE)) {
    188             /*
    189              * fill = default
    190              * The fill behavior for the element is determined by the value of the fillDefault
    191              * attribute.  This is the default value.
    192              */
    193             short fillDefault = getFillDefault();
    194             if (fillDefault != FILL_AUTO) {
    195                 return fillDefault;
    196             }
    197         }
    198 
    199         /*
    200          * fill = auto
    201          * The fill behavior for this element depends on whether the element specifies any of
    202          * the attributes that define the simple or active duration:
    203          *  - If none of the attributes dur, end, repeatCount or repeatDur are specified on
    204          *    the element, then the element will have a fill behavior identical to that if it were
    205          *    specified as "freeze".
    206          *  - Otherwise, the element will have a fill behavior identical to that if it were
    207          *    specified as "remove".
    208          */
    209         if (((mSmilElement.getAttribute("dur").length() == 0) &&
    210                 (mSmilElement.getAttribute("end").length() == 0) &&
    211                 (mSmilElement.getAttribute("repeatCount").length() == 0) &&
    212                 (mSmilElement.getAttribute("repeatDur").length() == 0)) ||
    213                 beginAndEndAreZero()) {
    214             return FILL_FREEZE;
    215         } else {
    216             return FILL_REMOVE;
    217         }
    218     }
    219 
    220     public short getFillDefault() {
    221         String fillDefault = mSmilElement.getAttribute(FILLDEFAULT_ATTRIBUTE_NAME);
    222         if (fillDefault.equalsIgnoreCase(FILL_REMOVE_ATTRIBUTE)) {
    223             return FILL_REMOVE;
    224         } else if (fillDefault.equalsIgnoreCase(FILL_FREEZE_ATTRIBUTE)) {
    225             return FILL_FREEZE;
    226         } else if (fillDefault.equalsIgnoreCase(FILL_AUTO_ATTRIBUTE)) {
    227             return FILL_AUTO;
    228         } else if (fillDefault.equalsIgnoreCase(FILL_HOLD_ATTRIBUTE)) {
    229             // FIXME handle it as freeze for now
    230             return FILL_FREEZE;
    231         } else if (fillDefault.equalsIgnoreCase(FILL_TRANSITION_ATTRIBUTE)) {
    232             // FIXME handle it as freeze for now
    233             return FILL_FREEZE;
    234         } else {
    235             /*
    236              * fillDefault = inherit
    237              * Specifies that the value of this attribute (and of the fill behavior) are
    238              * inherited from the fillDefault value of the parent element.
    239              * This is the default value.
    240              */
    241             ElementTime parent = getParentElementTime();
    242             if (parent == null) {
    243                 /*
    244                  * fillDefault = auto
    245                  * If there is no parent element, the value is "auto".
    246                  */
    247                 return FILL_AUTO;
    248             } else {
    249                 return ((ElementTimeImpl) parent).getFillDefault();
    250             }
    251         }
    252     }
    253 
    254     public float getRepeatCount() {
    255         String repeatCount = mSmilElement.getAttribute("repeatCount");
    256         try {
    257             float value = Float.parseFloat(repeatCount);
    258             if (value > 0) {
    259                 return value;
    260             } else {
    261                 return 0; // default
    262             }
    263         } catch (NumberFormatException e) {
    264             return 0; // default
    265         }
    266     }
    267 
    268     public float getRepeatDur() {
    269         try {
    270             float repeatDur =
    271                 TimeImpl.parseClockValue(mSmilElement.getAttribute("repeatDur"));
    272             if (repeatDur > 0) {
    273                 return repeatDur;
    274             } else {
    275                 return 0; // default
    276             }
    277         } catch (IllegalArgumentException e) {
    278             return 0; // default
    279         }
    280     }
    281 
    282     public short getRestart() {
    283         String restart = mSmilElement.getAttribute("restart");
    284         if (restart.equalsIgnoreCase("never")) {
    285             return RESTART_NEVER;
    286         } else if (restart.equalsIgnoreCase("whenNotActive")) {
    287             return RESTART_WHEN_NOT_ACTIVE;
    288         } else {
    289             return RESTART_ALWAYS; // default
    290         }
    291     }
    292 
    293     public void setBegin(TimeList begin) throws DOMException {
    294         // TODO Implement this
    295         mSmilElement.setAttribute("begin", "indefinite");
    296     }
    297 
    298     public void setDur(float dur) throws DOMException {
    299         // In SMIL 3.0, the dur could be a timecount-value which may contain fractions.
    300         // However, in MMS 1.3, the dur SHALL be expressed in integer milliseconds.
    301         mSmilElement.setAttribute("dur", Integer.toString((int)(dur * 1000)) + "ms");
    302     }
    303 
    304     public void setEnd(TimeList end) throws DOMException {
    305         // TODO Implement this
    306         mSmilElement.setAttribute("end", "indefinite");
    307     }
    308 
    309     public void setFill(short fill) throws DOMException {
    310         if (fill == FILL_FREEZE) {
    311             mSmilElement.setAttribute(FILL_ATTRIBUTE_NAME, FILL_FREEZE_ATTRIBUTE);
    312         } else {
    313             mSmilElement.setAttribute(FILL_ATTRIBUTE_NAME, FILL_REMOVE_ATTRIBUTE); // default
    314         }
    315     }
    316 
    317     public void setFillDefault(short fillDefault) throws DOMException {
    318         if (fillDefault == FILL_FREEZE) {
    319             mSmilElement.setAttribute(FILLDEFAULT_ATTRIBUTE_NAME, FILL_FREEZE_ATTRIBUTE);
    320         } else {
    321             mSmilElement.setAttribute(FILLDEFAULT_ATTRIBUTE_NAME, FILL_REMOVE_ATTRIBUTE);
    322         }
    323     }
    324 
    325     public void setRepeatCount(float repeatCount) throws DOMException {
    326         String repeatCountString = "indefinite";
    327         if (repeatCount > 0) {
    328             repeatCountString = Float.toString(repeatCount);
    329         }
    330         mSmilElement.setAttribute("repeatCount", repeatCountString);
    331     }
    332 
    333     public void setRepeatDur(float repeatDur) throws DOMException {
    334         String repeatDurString = "indefinite";
    335         if (repeatDur > 0) {
    336             repeatDurString = Float.toString(repeatDur) + "ms";
    337         }
    338         mSmilElement.setAttribute("repeatDur", repeatDurString);
    339     }
    340 
    341     public void setRestart(short restart) throws DOMException {
    342         if (restart == RESTART_NEVER) {
    343             mSmilElement.setAttribute("restart", "never");
    344         } else if (restart == RESTART_WHEN_NOT_ACTIVE) {
    345             mSmilElement.setAttribute("restart", "whenNotActive");
    346         } else {
    347             mSmilElement.setAttribute("restart", "always");
    348         }
    349     }
    350 }
    351