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