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