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     public short getFill() {
    163         String fill = mSmilElement.getAttribute(FILL_ATTRIBUTE_NAME);
    164         if (fill.equalsIgnoreCase(FILL_FREEZE_ATTRIBUTE)) {
    165             return FILL_FREEZE;
    166         } else if (fill.equalsIgnoreCase(FILL_REMOVE_ATTRIBUTE)) {
    167             return FILL_REMOVE;
    168         } else if (fill.equalsIgnoreCase(FILL_HOLD_ATTRIBUTE)) {
    169             // FIXME handle it as freeze for now
    170             return FILL_FREEZE;
    171         } else if (fill.equalsIgnoreCase(FILL_TRANSITION_ATTRIBUTE)) {
    172             // FIXME handle it as freeze for now
    173             return FILL_FREEZE;
    174         } else if (!fill.equalsIgnoreCase(FILL_AUTO_ATTRIBUTE)) {
    175             /*
    176              * fill = default
    177              * The fill behavior for the element is determined by the value of the fillDefault
    178              * attribute.  This is the default value.
    179              */
    180             short fillDefault = getFillDefault();
    181             if (fillDefault != FILL_AUTO) {
    182                 return fillDefault;
    183             }
    184         }
    185 
    186         /*
    187          * fill = auto
    188          * The fill behavior for this element depends on whether the element specifies any of
    189          * the attributes that define the simple or active duration:
    190          *  - If none of the attributes dur, end, repeatCount or repeatDur are specified on
    191          *    the element, then the element will have a fill behavior identical to that if it were
    192          *    specified as "freeze".
    193          *  - Otherwise, the element will have a fill behavior identical to that if it were
    194          *    specified as "remove".
    195          */
    196         if ((mSmilElement.getAttribute("dur").length() == 0) &&
    197                 (mSmilElement.getAttribute("end").length() == 0) &&
    198                 (mSmilElement.getAttribute("repeatCount").length() == 0) &&
    199                 (mSmilElement.getAttribute("repeatDur").length() == 0)) {
    200             return FILL_FREEZE;
    201         } else {
    202             return FILL_REMOVE;
    203         }
    204     }
    205 
    206     public short getFillDefault() {
    207         String fillDefault = mSmilElement.getAttribute(FILLDEFAULT_ATTRIBUTE_NAME);
    208         if (fillDefault.equalsIgnoreCase(FILL_REMOVE_ATTRIBUTE)) {
    209             return FILL_REMOVE;
    210         } else if (fillDefault.equalsIgnoreCase(FILL_FREEZE_ATTRIBUTE)) {
    211             return FILL_FREEZE;
    212         } else if (fillDefault.equalsIgnoreCase(FILL_AUTO_ATTRIBUTE)) {
    213             return FILL_AUTO;
    214         } else if (fillDefault.equalsIgnoreCase(FILL_HOLD_ATTRIBUTE)) {
    215             // FIXME handle it as freeze for now
    216             return FILL_FREEZE;
    217         } else if (fillDefault.equalsIgnoreCase(FILL_TRANSITION_ATTRIBUTE)) {
    218             // FIXME handle it as freeze for now
    219             return FILL_FREEZE;
    220         } else {
    221             /*
    222              * fillDefault = inherit
    223              * Specifies that the value of this attribute (and of the fill behavior) are
    224              * inherited from the fillDefault value of the parent element.
    225              * This is the default value.
    226              */
    227             ElementTime parent = getParentElementTime();
    228             if (parent == null) {
    229                 /*
    230                  * fillDefault = auto
    231                  * If there is no parent element, the value is "auto".
    232                  */
    233                 return FILL_AUTO;
    234             } else {
    235                 return ((ElementTimeImpl) parent).getFillDefault();
    236             }
    237         }
    238     }
    239 
    240     public float getRepeatCount() {
    241         String repeatCount = mSmilElement.getAttribute("repeatCount");
    242         try {
    243             float value = Float.parseFloat(repeatCount);
    244             if (value > 0) {
    245                 return value;
    246             } else {
    247                 return 0; // default
    248             }
    249         } catch (NumberFormatException e) {
    250             return 0; // default
    251         }
    252     }
    253 
    254     public float getRepeatDur() {
    255         try {
    256             float repeatDur =
    257                 TimeImpl.parseClockValue(mSmilElement.getAttribute("repeatDur"));
    258             if (repeatDur > 0) {
    259                 return repeatDur;
    260             } else {
    261                 return 0; // default
    262             }
    263         } catch (IllegalArgumentException e) {
    264             return 0; // default
    265         }
    266     }
    267 
    268     public short getRestart() {
    269         String restart = mSmilElement.getAttribute("restart");
    270         if (restart.equalsIgnoreCase("never")) {
    271             return RESTART_NEVER;
    272         } else if (restart.equalsIgnoreCase("whenNotActive")) {
    273             return RESTART_WHEN_NOT_ACTIVE;
    274         } else {
    275             return RESTART_ALWAYS; // default
    276         }
    277     }
    278 
    279     public void setBegin(TimeList begin) throws DOMException {
    280         // TODO Implement this
    281         mSmilElement.setAttribute("begin", "indefinite");
    282     }
    283 
    284     public void setDur(float dur) throws DOMException {
    285         // In SMIL 3.0, the dur could be a timecount-value which may contain fractions.
    286         // However, in MMS 1.3, the dur SHALL be expressed in integer milliseconds.
    287         mSmilElement.setAttribute("dur", Integer.toString((int)(dur * 1000)) + "ms");
    288     }
    289 
    290     public void setEnd(TimeList end) throws DOMException {
    291         // TODO Implement this
    292         mSmilElement.setAttribute("end", "indefinite");
    293     }
    294 
    295     public void setFill(short fill) throws DOMException {
    296         if (fill == FILL_FREEZE) {
    297             mSmilElement.setAttribute(FILL_ATTRIBUTE_NAME, FILL_FREEZE_ATTRIBUTE);
    298         } else {
    299             mSmilElement.setAttribute(FILL_ATTRIBUTE_NAME, FILL_REMOVE_ATTRIBUTE); // default
    300         }
    301     }
    302 
    303     public void setFillDefault(short fillDefault) throws DOMException {
    304         if (fillDefault == FILL_FREEZE) {
    305             mSmilElement.setAttribute(FILLDEFAULT_ATTRIBUTE_NAME, FILL_FREEZE_ATTRIBUTE);
    306         } else {
    307             mSmilElement.setAttribute(FILLDEFAULT_ATTRIBUTE_NAME, FILL_REMOVE_ATTRIBUTE);
    308         }
    309     }
    310 
    311     public void setRepeatCount(float repeatCount) throws DOMException {
    312         String repeatCountString = "indefinite";
    313         if (repeatCount > 0) {
    314             repeatCountString = Float.toString(repeatCount);
    315         }
    316         mSmilElement.setAttribute("repeatCount", repeatCountString);
    317     }
    318 
    319     public void setRepeatDur(float repeatDur) throws DOMException {
    320         String repeatDurString = "indefinite";
    321         if (repeatDur > 0) {
    322             repeatDurString = Float.toString(repeatDur) + "ms";
    323         }
    324         mSmilElement.setAttribute("repeatDur", repeatDurString);
    325     }
    326 
    327     public void setRestart(short restart) throws DOMException {
    328         if (restart == RESTART_NEVER) {
    329             mSmilElement.setAttribute("restart", "never");
    330         } else if (restart == RESTART_WHEN_NOT_ACTIVE) {
    331             mSmilElement.setAttribute("restart", "whenNotActive");
    332         } else {
    333             mSmilElement.setAttribute("restart", "always");
    334         }
    335     }
    336 }
    337