Format outgoing MMS using SMIL.

// FREEBIE

Closes #1879
This commit is contained in:
Jake McGinty 2014-06-28 14:06:15 -07:00 committed by Moxie Marlinspike
parent b355991b0b
commit 7441c191a7
32 changed files with 3878 additions and 41 deletions

View file

@ -19,6 +19,9 @@ repositories {
maven {
url "https://raw.github.com/whispersystems/maven/master/gson/releases/"
}
maven {
url "https://raw.github.com/whispersystems/maven/master/smil/releases/"
}
}
dependencies {
@ -27,6 +30,7 @@ dependencies {
compile 'se.emilsjolander:stickylistheaders:2.2.0'
compile 'com.google.android.gms:play-services:5.0.89'
compile 'com.astuetz:pagerslidingtabstrip:1.0.1'
compile 'org.w3c:smil:1.0.0'
androidTestCompile 'com.squareup:fest-android:1.0.8'
@ -40,6 +44,7 @@ dependencyVerification {
'se.emilsjolander:stickylistheaders:89146b46c96fea0e40200474a2625cda10fe94891e4128f53cdb42375091b9b6',
'com.google.android.gms:play-services:38f326e525830f1d70f60f594ceafcbdf5b312287ddbecd338fd1ed7958a4b1e',
'com.astuetz:pagerslidingtabstrip:f1641396732c7132a7abb837e482e5ee2b0ebb8d10813fc52bbaec2c15c184c2',
'org.w3c:smil:085dc40f2bb249651578bfa07499fd08b16ad0886dbe2c4078586a408da62f9b',
'com.google.protobuf:protobuf-java:ad9769a22989e688a46af4d3accc348cc501ced22118033230542bc916e33f0b',
'com.madgag:sc-light-jdk15on:931f39d351429fb96c2f749e7ecb1a256a8ebbf5edca7995c9cc085b94d1841d',
'com.googlecode.libphonenumber:libphonenumber:eba17eae81dd622ea89a00a3a8c025b2f25d342e0d9644c5b62e16f15687c3ab',

View file

@ -0,0 +1,108 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.TypeInfo;
public class AttrImpl extends NodeImpl implements Attr {
private String mName;
private String mValue;
/*
* Internal methods
*/
protected AttrImpl(DocumentImpl owner, String name) {
super(owner);
mName = name;
}
/*
* Attr Interface Methods
*/
public String getName() {
return mName;
}
public Element getOwnerElement() {
// TODO Auto-generated method stub
return null;
}
public boolean getSpecified() {
return mValue != null;
}
public String getValue() {
return mValue;
}
// Instead of setting a <code>Text></code> with the content of the
// String value as defined in the specs, we directly set here the
// internal mValue member.
public void setValue(String value) throws DOMException {
mValue = value;
}
/*
* Node Interface Methods
*/
@Override
public String getNodeName() {
return mName;
}
@Override
public short getNodeType() {
return Node.ATTRIBUTE_NODE;
}
@Override
public Node getParentNode() {
return null;
}
@Override
public Node getPreviousSibling() {
return null;
}
@Override
public Node getNextSibling() {
return null;
}
@Override
public void setNodeValue(String nodeValue) throws DOMException {
setValue(nodeValue);
}
public TypeInfo getSchemaTypeInfo() {
return null;
}
public boolean isId() {
return false;
}
}

View file

@ -0,0 +1,194 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom;
import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.DOMException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.EntityReference;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;
public abstract class DocumentImpl extends NodeImpl implements Document {
/*
* Internal methods
*/
public DocumentImpl() {
super(null);
}
/*
* Document Interface Methods
*/
public Attr createAttribute(String name) throws DOMException {
return new AttrImpl(this, name);
}
public Attr createAttributeNS(String namespaceURI, String qualifiedName)
throws DOMException {
// TODO Auto-generated method stub
return null;
}
public CDATASection createCDATASection(String data) throws DOMException {
// TODO Auto-generated method stub
return null;
}
public Comment createComment(String data) {
// TODO Auto-generated method stub
return null;
}
public DocumentFragment createDocumentFragment() {
// TODO Auto-generated method stub
return null;
}
public abstract Element createElement(String tagName) throws DOMException;
public Element createElementNS(String namespaceURI, String qualifiedName)
throws DOMException {
// TODO Auto-generated method stub
return null;
}
public EntityReference createEntityReference(String name) throws DOMException {
// TODO Auto-generated method stub
return null;
}
public ProcessingInstruction createProcessingInstruction(String target, String data)
throws DOMException {
// TODO Auto-generated method stub
return null;
}
public Text createTextNode(String data) {
// TODO Auto-generated method stub
return null;
}
public DocumentType getDoctype() {
// TODO Auto-generated method stub
return null;
}
public abstract Element getDocumentElement();
public Element getElementById(String elementId) {
// TODO Auto-generated method stub
return null;
}
public NodeList getElementsByTagName(String tagname) {
// TODO Auto-generated method stub
return null;
}
public NodeList getElementsByTagNameNS(String namespaceURI, String localName) {
// TODO Auto-generated method stub
return null;
}
public DOMImplementation getImplementation() {
// TODO Auto-generated method stub
return null;
}
public Node importNode(Node importedNode, boolean deep) throws DOMException {
// TODO Auto-generated method stub
return null;
}
/*
* Node Interface methods
*/
@Override
public short getNodeType() {
return Node.DOCUMENT_NODE;
}
@Override
public String getNodeName() {
// The value of nodeName is "#document" when Node is a Document
return "#document";
}
public String getInputEncoding() {
return null;
}
public String getXmlEncoding() {
return null;
}
public boolean getXmlStandalone() {
return false;
}
public void setXmlStandalone(boolean xmlStandalone) throws DOMException {}
public String getXmlVersion() {
return null;
}
public void setXmlVersion(String xmlVersion) throws DOMException {}
public boolean getStrictErrorChecking() {
return true;
}
public void setStrictErrorChecking(boolean strictErrorChecking) {}
public String getDocumentURI() {
return null;
}
public void setDocumentURI(String documentURI) {}
public Node adoptNode(Node source) throws DOMException {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
public DOMConfiguration getDomConfig() {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
public void normalizeDocument() {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
public Node renameNode(Node n, String namespaceURI, String qualifiedName)
throws DOMException {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
}

View file

@ -0,0 +1,172 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.w3c.dom.TypeInfo;
public class ElementImpl extends NodeImpl implements Element {
private String mTagName;
private NamedNodeMap mAttributes = new NamedNodeMapImpl();
/*
* Internal methods
*/
protected ElementImpl(DocumentImpl owner, String tagName) {
super(owner);
mTagName = tagName;
}
/*
* Element Interface methods
*/
public String getAttribute(String name) {
Attr attrNode = getAttributeNode(name);
String attrValue = "";
if (attrNode != null) {
attrValue = attrNode.getValue();
}
return attrValue;
}
public String getAttributeNS(String namespaceURI, String localName) {
// TODO Auto-generated method stub
return null;
}
public Attr getAttributeNode(String name) {
return (Attr)mAttributes.getNamedItem(name);
}
public Attr getAttributeNodeNS(String namespaceURI, String localName) {
// TODO Auto-generated method stub
return null;
}
public NodeList getElementsByTagName(String name) {
return new NodeListImpl(this, name, true);
}
public NodeList getElementsByTagNameNS(String namespaceURI, String localName) {
// TODO Auto-generated method stub
return null;
}
public String getTagName() {
return mTagName;
}
public boolean hasAttribute(String name) {
return (getAttributeNode(name) != null);
}
public boolean hasAttributeNS(String namespaceURI, String localName) {
// TODO Auto-generated method stub
return false;
}
public void removeAttribute(String name) throws DOMException {
// TODO Auto-generated method stub
}
public void removeAttributeNS(String namespaceURI, String localName)
throws DOMException {
// TODO Auto-generated method stub
}
public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
// TODO Auto-generated method stub
return null;
}
public void setAttribute(String name, String value) throws DOMException {
Attr attribute = getAttributeNode(name);
if (attribute == null) {
attribute = mOwnerDocument.createAttribute(name);
}
attribute.setNodeValue(value);
mAttributes.setNamedItem(attribute);
}
public void setAttributeNS(String namespaceURI, String qualifiedName,
String value) throws DOMException {
// TODO Auto-generated method stub
}
public Attr setAttributeNode(Attr newAttr) throws DOMException {
// TODO Auto-generated method stub
return null;
}
public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
// TODO Auto-generated method stub
return null;
}
/*
* Node Interface methods
*/
@Override
public short getNodeType() {
return ELEMENT_NODE;
}
@Override
public String getNodeName() {
// The value of nodeName is tagName when Node is an Element
return mTagName;
}
@Override
public NamedNodeMap getAttributes() {
return mAttributes;
}
@Override
public boolean hasAttributes() {
return (mAttributes.getLength() > 0);
}
public TypeInfo getSchemaTypeInfo() {
return null;
}
public void setIdAttribute(String name, boolean isId) throws DOMException {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
public void setIdAttributeNS(String namespaceURI, String localName,
boolean isId) throws DOMException {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
public void setIdAttributeNode(Attr idAttr, boolean isId)
throws DOMException {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom;
import java.util.Vector;
import org.w3c.dom.DOMException;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
public class NamedNodeMapImpl implements NamedNodeMap {
private Vector<Node> mNodes = new Vector<Node>();
public int getLength() {
return mNodes.size();
}
public Node getNamedItem(String name) {
Node node = null;
for (int i = 0; i < mNodes.size(); i++) {
if (name.equals(mNodes.elementAt(i).getNodeName())) {
node = mNodes.elementAt(i);
break;
}
}
return node;
}
public Node getNamedItemNS(String namespaceURI, String localName) {
// TODO Auto-generated method stub
return null;
}
public Node item(int index) {
if (index < mNodes.size()) {
return mNodes.elementAt(index);
}
return null;
}
public Node removeNamedItem(String name) throws DOMException {
Node node = getNamedItem(name);
if (node == null) {
throw new DOMException(DOMException.NOT_FOUND_ERR, "Not found");
} else {
mNodes.remove(node);
}
return node;
}
public Node removeNamedItemNS(String namespaceURI, String localName)
throws DOMException {
// TODO Auto-generated method stub
return null;
}
public Node setNamedItem(Node arg) throws DOMException {
Node existing = getNamedItem(arg.getNodeName());
if (existing != null) {
mNodes.remove(existing);
}
mNodes.add(arg);
return existing;
}
public Node setNamedItemNS(Node arg) throws DOMException {
// TODO Auto-generated method stub
return null;
}
}

View file

@ -0,0 +1,273 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom;
import java.util.NoSuchElementException;
import java.util.Vector;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.UserDataHandler;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventException;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
import org.thoughtcrime.securesms.dom.events.EventTargetImpl;
public abstract class NodeImpl implements Node, EventTarget {
private Node mParentNode;
private final Vector<Node> mChildNodes = new Vector<Node>();
DocumentImpl mOwnerDocument;
private final EventTarget mEventTarget = new EventTargetImpl(this);
/*
* Internal methods
*/
protected NodeImpl(DocumentImpl owner) {
mOwnerDocument = owner;
}
/*
* Node Interface Methods
*/
public Node appendChild(Node newChild) throws DOMException {
((NodeImpl)newChild).setParentNode(this);
mChildNodes.remove(newChild);
mChildNodes.add(newChild);
return newChild;
}
public Node cloneNode(boolean deep) {
// TODO Auto-generated method stub
return null;
}
public NamedNodeMap getAttributes() {
// Default. Override in Element.
return null;
}
public NodeList getChildNodes() {
return new NodeListImpl(this, null, false);
}
public Node getFirstChild() {
Node firstChild = null;
try {
firstChild = mChildNodes.firstElement();
}
catch (NoSuchElementException e) {
// Ignore and return null
}
return firstChild;
}
public Node getLastChild() {
Node lastChild = null;
try {
lastChild = mChildNodes.lastElement();
}
catch (NoSuchElementException e) {
// Ignore and return null
}
return lastChild;
}
public String getLocalName() {
// TODO Auto-generated method stub
return null;
}
public String getNamespaceURI() {
// TODO Auto-generated method stub
return null;
}
public Node getNextSibling() {
if ((mParentNode != null) && (this != mParentNode.getLastChild())) {
Vector<Node> siblings = ((NodeImpl)mParentNode).mChildNodes;
int indexOfThis = siblings.indexOf(this);
return siblings.elementAt(indexOfThis + 1);
}
return null;
}
public abstract String getNodeName();
public abstract short getNodeType();
public String getNodeValue() throws DOMException {
// Default behaviour. Override if required.
return null;
}
public Document getOwnerDocument() {
return mOwnerDocument;
}
public Node getParentNode() {
return mParentNode;
}
public String getPrefix() {
// TODO Auto-generated method stub
return null;
}
public Node getPreviousSibling() {
if ((mParentNode != null) && (this != mParentNode.getFirstChild())) {
Vector<Node> siblings = ((NodeImpl)mParentNode).mChildNodes;
int indexOfThis = siblings.indexOf(this);
return siblings.elementAt(indexOfThis - 1);
}
return null;
}
public boolean hasAttributes() {
// Default. Override in Element.
return false;
}
public boolean hasChildNodes() {
return !(mChildNodes.isEmpty());
}
public Node insertBefore(Node newChild, Node refChild) throws DOMException {
// TODO Auto-generated method stub
return null;
}
public boolean isSupported(String feature, String version) {
// TODO Auto-generated method stub
return false;
}
public void normalize() {
// TODO Auto-generated method stub
}
public Node removeChild(Node oldChild) throws DOMException {
if (mChildNodes.contains(oldChild)) {
mChildNodes.remove(oldChild);
((NodeImpl)oldChild).setParentNode(null);
} else {
throw new DOMException(DOMException.NOT_FOUND_ERR, "Child does not exist");
}
return null;
}
public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
if (mChildNodes.contains(oldChild)) {
// Try to remove the new child if available
try {
mChildNodes.remove(newChild);
} catch (DOMException e) {
// Ignore exception
}
mChildNodes.setElementAt(newChild, mChildNodes.indexOf(oldChild));
((NodeImpl)newChild).setParentNode(this);
((NodeImpl)oldChild).setParentNode(null);
} else {
throw new DOMException(DOMException.NOT_FOUND_ERR, "Old child does not exist");
}
return oldChild;
}
public void setNodeValue(String nodeValue) throws DOMException {
// Default behaviour. Override if required.
}
public void setPrefix(String prefix) throws DOMException {
// TODO Auto-generated method stub
}
private void setParentNode(Node parentNode) {
mParentNode = parentNode;
}
/*
* EventTarget Interface
*/
public void addEventListener(String type, EventListener listener, boolean useCapture) {
mEventTarget.addEventListener(type, listener, useCapture);
}
public void removeEventListener(String type, EventListener listener, boolean useCapture) {
mEventTarget.removeEventListener(type, listener, useCapture);
}
public boolean dispatchEvent(Event evt) throws EventException {
return mEventTarget.dispatchEvent(evt);
}
public String getBaseURI() {
return null;
}
public short compareDocumentPosition(Node other) throws DOMException {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
public String getTextContent() throws DOMException {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
public void setTextContent(String textContent) throws DOMException {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
public boolean isSameNode(Node other) {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
public String lookupPrefix(String namespaceURI) {
return null;
}
public boolean isDefaultNamespace(String namespaceURI) {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
public String lookupNamespaceURI(String prefix) {
return null;
}
public boolean isEqualNode(Node arg) {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
public Object getFeature(String feature, String version) {
return null;
}
public Object setUserData(String key, Object data,
UserDataHandler handler) {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, null);
}
public Object getUserData(String key) {
return null;
}
}

View file

@ -0,0 +1,128 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom;
import java.util.ArrayList;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class NodeListImpl implements NodeList {
private ArrayList<Node> mSearchNodes;
private ArrayList<Node> mStaticNodes;
private Node mRootNode;
private String mTagName;
private boolean mDeepSearch;
/*
* Internal Interface
*/
/**
* Constructs a NodeList by searching for all descendants or the direct
* children of a root node with a given tag name.
* @param rootNode The root <code>Node</code> of the search.
* @param tagName The tag name to be searched for. If null, all descendants
* will be returned.
* @param deep Limit the search to the direct children of rootNode if false,
* to all descendants otherwise.
*/
public NodeListImpl(Node rootNode, String tagName, boolean deepSearch) {
mRootNode = rootNode;
mTagName = tagName;
mDeepSearch = deepSearch;
}
/**
* Constructs a NodeList for a given static node list.
* @param nodes The static node list.
*/
public NodeListImpl(ArrayList<Node> nodes) {
mStaticNodes = nodes;
}
/*
* NodeListImpl Interface
*/
public int getLength() {
if (mStaticNodes == null) {
fillList(mRootNode);
return mSearchNodes.size();
} else {
return mStaticNodes.size();
}
}
public Node item(int index) {
Node node = null;
if (mStaticNodes == null) {
fillList(mRootNode);
try {
node = mSearchNodes.get(index);
} catch (IndexOutOfBoundsException e) {
// Do nothing and return null
}
} else {
try {
node = mStaticNodes.get(index);
} catch (IndexOutOfBoundsException e) {
// Do nothing and return null
}
}
return node;
}
/**
* A preorder traversal is done in the following order:
* <ul>
* <li> Visit root.
* <li> Traverse children from left to right in preorder.
* </ul>
* This method fills the live node list.
* @param The root of preorder traversal
* @return The next match
*/
private void fillList(Node node) {
// (Re)-initialize the container if this is the start of the search.
// Visit the root of this iteration otherwise.
if (node == mRootNode) {
mSearchNodes = new ArrayList<Node>();
} else {
if ((mTagName == null) || node.getNodeName().equals(mTagName)) {
mSearchNodes.add(node);
}
}
// Descend one generation...
node = node.getFirstChild();
// ...and visit in preorder the children if we are in deep search
// or directly add the children to the list otherwise.
while (node != null) {
if (mDeepSearch) {
fillList(node);
} else {
if ((mTagName == null) || node.getNodeName().equals(mTagName)) {
mSearchNodes.add(node);
}
}
node = node.getNextSibling();
}
}
}

View file

@ -0,0 +1,127 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.events;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventTarget;
public class EventImpl implements Event {
// Event type informations
private String mEventType;
private boolean mCanBubble;
private boolean mCancelable;
// Flags whether the event type information was set
// FIXME: Can we use mEventType for this purpose?
private boolean mInitialized;
// Target of this event
private EventTarget mTarget;
// Event status variables
private short mEventPhase;
private boolean mStopPropagation;
private boolean mPreventDefault;
private EventTarget mCurrentTarget;
private int mSeekTo;
private final long mTimeStamp = System.currentTimeMillis();
public boolean getBubbles() {
return mCanBubble;
}
public boolean getCancelable() {
return mCancelable;
}
public EventTarget getCurrentTarget() {
return mCurrentTarget;
}
public short getEventPhase() {
return mEventPhase;
}
public EventTarget getTarget() {
return mTarget;
}
public long getTimeStamp() {
return mTimeStamp;
}
public String getType() {
return mEventType;
}
public void initEvent(String eventTypeArg, boolean canBubbleArg,
boolean cancelableArg) {
mEventType = eventTypeArg;
mCanBubble = canBubbleArg;
mCancelable = cancelableArg;
mInitialized = true;
}
public void initEvent(String eventTypeArg, boolean canBubbleArg, boolean cancelableArg,
int seekTo) {
mSeekTo = seekTo;
initEvent(eventTypeArg, canBubbleArg, cancelableArg);
}
public void preventDefault() {
mPreventDefault = true;
}
public void stopPropagation() {
mStopPropagation = true;
}
/*
* Internal Interface
*/
boolean isInitialized() {
return mInitialized;
}
boolean isPreventDefault() {
return mPreventDefault;
}
boolean isPropogationStopped() {
return mStopPropagation;
}
void setTarget(EventTarget target) {
mTarget = target;
}
void setEventPhase(short eventPhase) {
mEventPhase = eventPhase;
}
void setCurrentTarget(EventTarget currentTarget) {
mCurrentTarget = currentTarget;
}
public int getSeekTo() {
return mSeekTo;
}
}

View file

@ -0,0 +1,131 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.events;
import java.util.ArrayList;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventException;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
import android.util.Log;
public class EventTargetImpl implements EventTarget {
private static final String TAG = "EventTargetImpl";
private ArrayList<EventListenerEntry> mListenerEntries;
private EventTarget mNodeTarget;
static class EventListenerEntry
{
final String mType;
final EventListener mListener;
final boolean mUseCapture;
EventListenerEntry(String type, EventListener listener, boolean useCapture)
{
mType = type;
mListener = listener;
mUseCapture = useCapture;
}
}
public EventTargetImpl(EventTarget target) {
mNodeTarget = target;
}
public void addEventListener(String type, EventListener listener, boolean useCapture) {
if ((type == null) || type.equals("") || (listener == null)) {
return;
}
// Make sure we have only one entry
removeEventListener(type, listener, useCapture);
if (mListenerEntries == null) {
mListenerEntries = new ArrayList<EventListenerEntry>();
}
mListenerEntries.add(new EventListenerEntry(type, listener, useCapture));
}
public boolean dispatchEvent(Event evt) throws EventException {
// We need to use the internal APIs to modify and access the event status
EventImpl eventImpl = (EventImpl)evt;
if (!eventImpl.isInitialized()) {
throw new EventException(EventException.UNSPECIFIED_EVENT_TYPE_ERR,
"Event not initialized");
} else if ((eventImpl.getType() == null) || eventImpl.getType().equals("")) {
throw new EventException(EventException.UNSPECIFIED_EVENT_TYPE_ERR,
"Unspecified even type");
}
// Initialize event status
eventImpl.setTarget(mNodeTarget);
// TODO: At this point, to support event capturing and bubbling, we should
// establish the chain of EventTargets from the top of the tree to this
// event's target.
// TODO: CAPTURING_PHASE skipped
// Handle AT_TARGET
// Invoke handleEvent of non-capturing listeners on this EventTarget.
eventImpl.setEventPhase(Event.AT_TARGET);
eventImpl.setCurrentTarget(mNodeTarget);
if (!eventImpl.isPropogationStopped() && (mListenerEntries != null)) {
for (int i = 0; i < mListenerEntries.size(); i++) {
EventListenerEntry listenerEntry = mListenerEntries.get(i);
if (!listenerEntry.mUseCapture
&& listenerEntry.mType.equals(eventImpl.getType())) {
try {
listenerEntry.mListener.handleEvent(eventImpl);
}
catch (Exception e) {
// Any exceptions thrown inside an EventListener will
// not stop propagation of the event
Log.w(TAG, "Catched EventListener exception", e);
}
}
}
}
if (eventImpl.getBubbles()) {
// TODO: BUBBLING_PHASE skipped
}
return eventImpl.isPreventDefault();
}
public void removeEventListener(String type, EventListener listener,
boolean useCapture) {
if (null == mListenerEntries) {
return;
}
for (int i = 0; i < mListenerEntries.size(); i ++) {
EventListenerEntry listenerEntry = mListenerEntries.get(i);
if ((listenerEntry.mUseCapture == useCapture)
&& (listenerEntry.mListener == listener)
&& listenerEntry.mType.equals(type)) {
mListenerEntries.remove(i);
break;
}
}
}
}

View file

@ -0,0 +1,155 @@
/*
* 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 org.thoughtcrime.securesms.dom.smil;
import java.util.ArrayList;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.smil.ElementParallelTimeContainer;
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 org.thoughtcrime.securesms.dom.NodeListImpl;
public abstract class ElementParallelTimeContainerImpl extends ElementTimeContainerImpl
implements ElementParallelTimeContainer {
private final static String ENDSYNC_ATTRIBUTE_NAME = "endsync";
private final static String ENDSYNC_FIRST = "first";
private final static String ENDSYNC_LAST = "last";
private final static String ENDSYNC_ALL = "all";
private final static String ENDSYNC_MEDIA = "media";
/*
* Internal Interface
*/
ElementParallelTimeContainerImpl(SMILElement element) {
super(element);
}
public String getEndSync() {
String endsync = mSmilElement.getAttribute(ENDSYNC_ATTRIBUTE_NAME);
if ((endsync == null) || (endsync.length() == 0)) {
setEndSync(ENDSYNC_LAST);
return ENDSYNC_LAST;
}
if (ENDSYNC_FIRST.equals(endsync) || ENDSYNC_LAST.equals(endsync) ||
ENDSYNC_ALL.equals(endsync) || ENDSYNC_MEDIA.equals(endsync)) {
return endsync;
}
// FIXME add the checking for ID-Value and smil1.0-Id-value.
setEndSync(ENDSYNC_LAST);
return ENDSYNC_LAST;
}
public void setEndSync(String endSync) throws DOMException {
if (ENDSYNC_FIRST.equals(endSync) || ENDSYNC_LAST.equals(endSync) ||
ENDSYNC_ALL.equals(endSync) || ENDSYNC_MEDIA.equals(endSync)) {
mSmilElement.setAttribute(ENDSYNC_ATTRIBUTE_NAME, endSync);
} else { // FIXME add the support for ID-Value and smil1.0-Id-value.
throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
"Unsupported endsync value" + endSync);
}
}
@Override
public float getDur() {
float dur = super.getDur();
if (dur == 0) {
dur = getImplicitDuration();
}
return dur;
}
public float getImplicitDuration() {
float dur = -1.0F;
if (ENDSYNC_LAST.equals(getEndSync())) {
NodeList children = getTimeChildren();
for (int i = 0; i < children.getLength(); ++i) {
ElementTime child = (ElementTime) children.item(i);
TimeList endTimeList = child.getEnd();
for (int j = 0; j < endTimeList.getLength(); ++j) {
Time endTime = endTimeList.item(j);
if (endTime.getTimeType() == Time.SMIL_TIME_INDEFINITE) {
// Return "indefinite" here.
return -1.0F;
}
if (endTime.getResolved()) {
float end = (float)endTime.getResolvedOffset();
dur = (end > dur) ? end : dur;
}
}
}
} // Other endsync types are not supported now.
return dur;
}
public NodeList getActiveChildrenAt(float instant) {
/*
* Find the closest Time of ElementTime before instant.
* Add ElementTime to list of active elements if the Time belongs to the begin-list,
* do not add it otherwise.
*/
ArrayList<Node> activeChildren = new ArrayList<Node>();
NodeList children = getTimeChildren();
int childrenLen = children.getLength();
for (int i = 0; i < childrenLen; ++i) {
double maxOffset = 0.0;
boolean active = false;
ElementTime child = (ElementTime) children.item(i);
TimeList beginList = child.getBegin();
int len = beginList.getLength();
for (int j = 0; j < len; ++j) {
Time begin = beginList.item(j);
if (begin.getResolved()) {
double resolvedOffset = begin.getResolvedOffset() * 1000.0;
if ((resolvedOffset <= instant) && (resolvedOffset >= maxOffset)) {
maxOffset = resolvedOffset;
active = true;
}
}
}
TimeList endList = child.getEnd();
len = endList.getLength();
for (int j = 0; j < len; ++j) {
Time end = endList.item(j);
if (end.getResolved()) {
double resolvedOffset = end.getResolvedOffset() * 1000.0;
if ((resolvedOffset <= instant) && (resolvedOffset >= maxOffset)) {
maxOffset = resolvedOffset;
active = false;
}
}
}
if (active) {
activeChildren.add((Node) child);
}
}
return new NodeListImpl(activeChildren);
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.smil;
import java.util.ArrayList;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.smil.ElementSequentialTimeContainer;
import org.w3c.dom.smil.ElementTime;
import org.w3c.dom.smil.SMILElement;
import org.thoughtcrime.securesms.dom.NodeListImpl;
public abstract class ElementSequentialTimeContainerImpl extends
ElementTimeContainerImpl implements ElementSequentialTimeContainer {
/*
* Internal Interface
*/
ElementSequentialTimeContainerImpl(SMILElement element) {
super(element);
}
/*
* ElementSequentialTimeContainer Interface
*/
public NodeList getActiveChildrenAt(float instant) {
NodeList allChildren = this.getTimeChildren();
ArrayList<Node> nodes = new ArrayList<Node>();
for (int i = 0; i < allChildren.getLength(); i++) {
instant -= ((ElementTime) allChildren.item(i)).getDur();
if (instant < 0) {
nodes.add(allChildren.item(i));
return new NodeListImpl(nodes);
}
}
return new NodeListImpl(nodes);
}
public float getDur() {
float dur = super.getDur();
if (dur == 0) {
NodeList children = getTimeChildren();
for (int i = 0; i < children.getLength(); ++i) {
ElementTime child = (ElementTime) children.item(i);
if (child.getDur() < 0) {
// Return "indefinite" since containing a child whose duration is indefinite.
return -1.0F;
}
dur += child.getDur();
}
}
return dur;
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.smil;
import org.w3c.dom.smil.ElementTimeContainer;
import org.w3c.dom.smil.SMILElement;
public abstract class ElementTimeContainerImpl extends ElementTimeImpl implements
ElementTimeContainer {
/*
* Internal Interface
*/
ElementTimeContainerImpl(SMILElement element) {
super(element);
}
}

View file

@ -0,0 +1,348 @@
/*
* 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 org.thoughtcrime.securesms.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");
}
}
}

View file

@ -0,0 +1,291 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.smil;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.events.DocumentEvent;
import org.w3c.dom.events.Event;
import org.w3c.dom.smil.ElementSequentialTimeContainer;
import org.w3c.dom.smil.ElementTime;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILElement;
import org.w3c.dom.smil.SMILLayoutElement;
import org.w3c.dom.smil.TimeList;
import org.thoughtcrime.securesms.dom.DocumentImpl;
import org.thoughtcrime.securesms.dom.events.EventImpl;
public class SmilDocumentImpl extends DocumentImpl implements SMILDocument, DocumentEvent {
/*
* The sequential time container cannot be initialized here because the real container
* is body, which hasn't been created yet. It will be initialized when the body has
* already been created. Please see getBody().
*/
ElementSequentialTimeContainer mSeqTimeContainer;
public final static String SMIL_DOCUMENT_START_EVENT = "SmilDocumentStart";
public final static String SMIL_DOCUMENT_END_EVENT = "SimlDocumentEnd";
/*
* Internal methods
*/
public SmilDocumentImpl() {
super();
}
/*
* ElementSequentialTimeContainer stuff
*/
public NodeList getActiveChildrenAt(float instant) {
return mSeqTimeContainer.getActiveChildrenAt(instant);
}
public NodeList getTimeChildren() {
return mSeqTimeContainer.getTimeChildren();
}
public boolean beginElement() {
return mSeqTimeContainer.beginElement();
}
public boolean endElement() {
return mSeqTimeContainer.endElement();
}
public TimeList getBegin() {
return mSeqTimeContainer.getBegin();
}
public float getDur() {
return mSeqTimeContainer.getDur();
}
public TimeList getEnd() {
return mSeqTimeContainer.getEnd();
}
public short getFill() {
return mSeqTimeContainer.getFill();
}
public short getFillDefault() {
return mSeqTimeContainer.getFillDefault();
}
public float getRepeatCount() {
return mSeqTimeContainer.getRepeatCount();
}
public float getRepeatDur() {
return mSeqTimeContainer.getRepeatDur();
}
public short getRestart() {
return mSeqTimeContainer.getRestart();
}
public void pauseElement() {
mSeqTimeContainer.pauseElement();
}
public void resumeElement() {
mSeqTimeContainer.resumeElement();
}
public void seekElement(float seekTo) {
mSeqTimeContainer.seekElement(seekTo);
}
public void setBegin(TimeList begin) throws DOMException {
mSeqTimeContainer.setBegin(begin);
}
public void setDur(float dur) throws DOMException {
mSeqTimeContainer.setDur(dur);
}
public void setEnd(TimeList end) throws DOMException {
mSeqTimeContainer.setEnd(end);
}
public void setFill(short fill) throws DOMException {
mSeqTimeContainer.setFill(fill);
}
public void setFillDefault(short fillDefault) throws DOMException {
mSeqTimeContainer.setFillDefault(fillDefault);
}
public void setRepeatCount(float repeatCount) throws DOMException {
mSeqTimeContainer.setRepeatCount(repeatCount);
}
public void setRepeatDur(float repeatDur) throws DOMException {
mSeqTimeContainer.setRepeatDur(repeatDur);
}
public void setRestart(short restart) throws DOMException {
mSeqTimeContainer.setRestart(restart);
}
/*
* Document Interface
*/
@Override
public Element createElement(String tagName) throws DOMException {
// Find the appropriate class for this element
tagName = tagName.toLowerCase();
if (tagName.equals("text") ||
tagName.equals("img") ||
tagName.equals("video")) {
return new SmilRegionMediaElementImpl(this, tagName);
} else if (tagName.equals("audio")) {
return new SmilMediaElementImpl(this, tagName);
} else if (tagName.equals("layout")) {
return new SmilLayoutElementImpl(this, tagName);
} else if (tagName.equals("root-layout")) {
return new SmilRootLayoutElementImpl(this, tagName);
} else if (tagName.equals("region")) {
return new SmilRegionElementImpl(this, tagName);
} else if (tagName.equals("ref")) {
return new SmilRefElementImpl(this, tagName);
} else if (tagName.equals("par")) {
return new SmilParElementImpl(this, tagName);
} else {
// This includes also the structural nodes SMIL,
// HEAD, BODY, for which no specific types are defined.
return new SmilElementImpl(this, tagName);
}
}
@Override
public SMILElement getDocumentElement() {
Node rootElement = getFirstChild();
if (rootElement == null || !(rootElement instanceof SMILElement)) {
// The root doesn't exist. Create a new one.
rootElement = createElement("smil");
appendChild(rootElement);
}
return (SMILElement) rootElement;
}
/*
* SMILElement Interface
*/
public SMILElement getHead() {
Node rootElement = getDocumentElement();
Node headElement = rootElement.getFirstChild();
if (headElement == null || !(headElement instanceof SMILElement)) {
// The head doesn't exist. Create a new one.
headElement = createElement("head");
rootElement.appendChild(headElement);
}
return (SMILElement) headElement;
}
public SMILElement getBody() {
Node rootElement = getDocumentElement();
Node headElement = getHead();
Node bodyElement = headElement.getNextSibling();
if (bodyElement == null || !(bodyElement instanceof SMILElement)) {
// The body doesn't exist. Create a new one.
bodyElement = createElement("body");
rootElement.appendChild(bodyElement);
}
// Initialize the real sequential time container, which is body.
mSeqTimeContainer = new ElementSequentialTimeContainerImpl((SMILElement) bodyElement) {
public NodeList getTimeChildren() {
return getBody().getElementsByTagName("par");
}
public boolean beginElement() {
Event startEvent = createEvent("Event");
startEvent.initEvent(SMIL_DOCUMENT_START_EVENT, false, false);
dispatchEvent(startEvent);
return true;
}
public boolean endElement() {
Event endEvent = createEvent("Event");
endEvent.initEvent(SMIL_DOCUMENT_END_EVENT, false, false);
dispatchEvent(endEvent);
return true;
}
public void pauseElement() {
// TODO Auto-generated method stub
}
public void resumeElement() {
// TODO Auto-generated method stub
}
public void seekElement(float seekTo) {
// TODO Auto-generated method stub
}
ElementTime getParentElementTime() {
return null;
}
};
return (SMILElement) bodyElement;
}
public SMILLayoutElement getLayout() {
Node headElement = getHead();
Node layoutElement = null;
// Find the layout element under <code>HEAD</code>
layoutElement = headElement.getFirstChild();
while ((layoutElement != null) && !(layoutElement instanceof SMILLayoutElement)) {
layoutElement = layoutElement.getNextSibling();
}
if (layoutElement == null) {
// The layout doesn't exist. Create a default one.
layoutElement = new SmilLayoutElementImpl(this, "layout");
headElement.appendChild(layoutElement);
}
return (SMILLayoutElement) layoutElement;
}
/*
* DocumentEvent Interface
*/
public Event createEvent(String eventType) throws DOMException {
if ("Event".equals(eventType)) {
return new EventImpl();
} else {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
"Not supported interface");
}
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.smil;
import org.w3c.dom.DOMException;
import org.w3c.dom.smil.SMILElement;
import org.thoughtcrime.securesms.dom.ElementImpl;
public class SmilElementImpl extends ElementImpl implements SMILElement {
/**
* This constructor is used by the factory methods of the SmilDocument.
*
* @param owner The SMIL document to which this element belongs to
* @param tagName The tag name of the element
*/
SmilElementImpl(SmilDocumentImpl owner, String tagName)
{
super(owner, tagName.toLowerCase());
}
public String getId() {
// TODO Auto-generated method stub
return null;
}
public void setId(String id) throws DOMException {
// TODO Auto-generated method stub
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.smil;
import org.thoughtcrime.securesms.util.SmilUtil;
import org.w3c.dom.NodeList;
import org.w3c.dom.smil.SMILLayoutElement;
import org.w3c.dom.smil.SMILRootLayoutElement;
public class SmilLayoutElementImpl extends SmilElementImpl implements
SMILLayoutElement {
SmilLayoutElementImpl(SmilDocumentImpl owner, String tagName) {
super(owner, tagName);
}
public boolean getResolved() {
// TODO Auto-generated method stub
return false;
}
public String getType() {
return this.getAttribute("type");
}
public NodeList getRegions() {
return this.getElementsByTagName("region");
}
public SMILRootLayoutElement getRootLayout() {
NodeList childNodes = this.getChildNodes();
SMILRootLayoutElement rootLayoutNode = null;
int childrenCount = childNodes.getLength();
for (int i = 0; i < childrenCount; i++) {
if (childNodes.item(i).getNodeName().equals("root-layout")) {
rootLayoutNode = (SMILRootLayoutElement)childNodes.item(i);
}
}
if (null == rootLayoutNode) {
// root-layout node is not set. Create a default one.
rootLayoutNode = (SMILRootLayoutElement) getOwnerDocument().createElement("root-layout");
rootLayoutNode.setWidth(SmilUtil.ROOT_WIDTH);
rootLayoutNode.setHeight(SmilUtil.ROOT_HEIGHT);
appendChild(rootLayoutNode);
}
return rootLayoutNode;
}
}

View file

@ -0,0 +1,343 @@
/*
* 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 org.thoughtcrime.securesms.dom.smil;
import org.w3c.dom.DOMException;
import org.w3c.dom.events.DocumentEvent;
import org.w3c.dom.events.Event;
import org.w3c.dom.smil.ElementTime;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.TimeList;
import android.util.Log;
import org.thoughtcrime.securesms.dom.events.EventImpl;
public class SmilMediaElementImpl extends SmilElementImpl implements
SMILMediaElement {
public final static String SMIL_MEDIA_START_EVENT = "SmilMediaStart";
public final static String SMIL_MEDIA_END_EVENT = "SmilMediaEnd";
public final static String SMIL_MEDIA_PAUSE_EVENT = "SmilMediaPause";
public final static String SMIL_MEDIA_SEEK_EVENT = "SmilMediaSeek";
private final static String TAG = "Mms:smil";
private static final boolean DEBUG = false;
private static final boolean LOCAL_LOGV = false;
ElementTime mElementTime = new ElementTimeImpl(this) {
private Event createEvent(String eventType) {
DocumentEvent doc =
(DocumentEvent)SmilMediaElementImpl.this.getOwnerDocument();
Event event = doc.createEvent("Event");
event.initEvent(eventType, false, false);
if (LOCAL_LOGV) {
Log.v(TAG, "Dispatching 'begin' event to "
+ SmilMediaElementImpl.this.getTagName() + " "
+ SmilMediaElementImpl.this.getSrc() + " at "
+ System.currentTimeMillis());
}
return event;
}
private Event createEvent(String eventType, int seekTo) {
DocumentEvent doc =
(DocumentEvent)SmilMediaElementImpl.this.getOwnerDocument();
EventImpl event = (EventImpl) doc.createEvent("Event");
event.initEvent(eventType, false, false, seekTo);
if (LOCAL_LOGV) {
Log.v(TAG, "Dispatching 'begin' event to "
+ SmilMediaElementImpl.this.getTagName() + " "
+ SmilMediaElementImpl.this.getSrc() + " at "
+ System.currentTimeMillis());
}
return event;
}
public boolean beginElement() {
Event startEvent = createEvent(SMIL_MEDIA_START_EVENT);
dispatchEvent(startEvent);
return true;
}
public boolean endElement() {
Event endEvent = createEvent(SMIL_MEDIA_END_EVENT);
dispatchEvent(endEvent);
return true;
}
public void resumeElement() {
Event resumeEvent = createEvent(SMIL_MEDIA_START_EVENT);
dispatchEvent(resumeEvent);
}
public void pauseElement() {
Event pauseEvent = createEvent(SMIL_MEDIA_PAUSE_EVENT);
dispatchEvent(pauseEvent);
}
public void seekElement(float seekTo) {
Event seekEvent = createEvent(SMIL_MEDIA_SEEK_EVENT, (int) seekTo);
dispatchEvent(seekEvent);
}
@Override
public float getDur() {
float dur = super.getDur();
if (dur == 0) {
// Duration is not specified, So get the implicit duration.
String tag = getTagName();
if (tag.equals("video") || tag.equals("audio")) {
// Continuous media
// FIXME Should get the duration of the media. "indefinite" instead here.
dur = -1.0F;
} else if (tag.equals("text") || tag.equals("img")) {
// Discrete media
dur = 0;
} else {
Log.w(TAG, "Unknown media type");
}
}
return dur;
}
@Override
ElementTime getParentElementTime() {
return ((SmilParElementImpl) mSmilElement.getParentNode()).mParTimeContainer;
}
};
/*
* Internal Interface
*/
SmilMediaElementImpl(SmilDocumentImpl owner, String tagName) {
super(owner, tagName);
}
/*
* SMILMediaElement Interface
*/
public String getAbstractAttr() {
return this.getAttribute("abstract");
}
public String getAlt() {
return this.getAttribute("alt");
}
public String getAuthor() {
return this.getAttribute("author");
}
public String getClipBegin() {
return this.getAttribute("clipBegin");
}
public String getClipEnd() {
return this.getAttribute("clipEnd");
}
public String getCopyright() {
return this.getAttribute("copyright");
}
public String getLongdesc() {
return this.getAttribute("longdesc");
}
public String getPort() {
return this.getAttribute("port");
}
public String getReadIndex() {
return this.getAttribute("readIndex");
}
public String getRtpformat() {
return this.getAttribute("rtpformat");
}
public String getSrc() {
return this.getAttribute("src");
}
public String getStripRepeat() {
return this.getAttribute("stripRepeat");
}
public String getTitle() {
return this.getAttribute("title");
}
public String getTransport() {
return this.getAttribute("transport");
}
public String getType() {
return this.getAttribute("type");
}
public void setAbstractAttr(String abstractAttr) throws DOMException {
this.setAttribute("abstract", abstractAttr);
}
public void setAlt(String alt) throws DOMException {
this.setAttribute("alt", alt);
}
public void setAuthor(String author) throws DOMException {
this.setAttribute("author", author);
}
public void setClipBegin(String clipBegin) throws DOMException {
this.setAttribute("clipBegin", clipBegin);
}
public void setClipEnd(String clipEnd) throws DOMException {
this.setAttribute("clipEnd", clipEnd);
}
public void setCopyright(String copyright) throws DOMException {
this.setAttribute("copyright", copyright);
}
public void setLongdesc(String longdesc) throws DOMException {
this.setAttribute("longdesc", longdesc);
}
public void setPort(String port) throws DOMException {
this.setAttribute("port", port);
}
public void setReadIndex(String readIndex) throws DOMException {
this.setAttribute("readIndex", readIndex);
}
public void setRtpformat(String rtpformat) throws DOMException {
this.setAttribute("rtpformat", rtpformat);
}
public void setSrc(String src) throws DOMException {
this.setAttribute("src", src);
}
public void setStripRepeat(String stripRepeat) throws DOMException {
this.setAttribute("stripRepeat", stripRepeat);
}
public void setTitle(String title) throws DOMException {
this.setAttribute("title", title);
}
public void setTransport(String transport) throws DOMException {
this.setAttribute("transport", transport);
}
public void setType(String type) throws DOMException {
this.setAttribute("type", type);
}
/*
* TimeElement Interface
*/
public boolean beginElement() {
return mElementTime.beginElement();
}
public boolean endElement() {
return mElementTime.endElement();
}
public TimeList getBegin() {
return mElementTime.getBegin();
}
public float getDur() {
return mElementTime.getDur();
}
public TimeList getEnd() {
return mElementTime.getEnd();
}
public short getFill() {
return mElementTime.getFill();
}
public short getFillDefault() {
return mElementTime.getFillDefault();
}
public float getRepeatCount() {
return mElementTime.getRepeatCount();
}
public float getRepeatDur() {
return mElementTime.getRepeatDur();
}
public short getRestart() {
return mElementTime.getRestart();
}
public void pauseElement() {
mElementTime.pauseElement();
}
public void resumeElement() {
mElementTime.resumeElement();
}
public void seekElement(float seekTo) {
mElementTime.seekElement(seekTo);
}
public void setBegin(TimeList begin) throws DOMException {
mElementTime.setBegin(begin);
}
public void setDur(float dur) throws DOMException {
mElementTime.setDur(dur);
}
public void setEnd(TimeList end) throws DOMException {
mElementTime.setEnd(end);
}
public void setFill(short fill) throws DOMException {
mElementTime.setFill(fill);
}
public void setFillDefault(short fillDefault) throws DOMException {
mElementTime.setFillDefault(fillDefault);
}
public void setRepeatCount(float repeatCount) throws DOMException {
mElementTime.setRepeatCount(repeatCount);
}
public void setRepeatDur(float repeatDur) throws DOMException {
mElementTime.setRepeatDur(repeatDur);
}
public void setRestart(short restart) throws DOMException {
mElementTime.setRestart(restart);
}
}

View file

@ -0,0 +1,217 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.smil;
import java.util.ArrayList;
import org.w3c.dom.DOMException;
import org.w3c.dom.NodeList;
import org.w3c.dom.events.DocumentEvent;
import org.w3c.dom.events.Event;
import org.w3c.dom.smil.ElementParallelTimeContainer;
import org.w3c.dom.smil.ElementTime;
import org.w3c.dom.smil.SMILParElement;
import org.w3c.dom.smil.Time;
import org.w3c.dom.smil.TimeList;
public class SmilParElementImpl extends SmilElementImpl implements SMILParElement {
public final static String SMIL_SLIDE_START_EVENT = "SmilSlideStart";
public final static String SMIL_SLIDE_END_EVENT = "SmilSlideEnd";
ElementParallelTimeContainer mParTimeContainer =
new ElementParallelTimeContainerImpl(this) {
@Override
public TimeList getBegin() {
/*
* For children of a sequence, the only legal value for begin is
* a (single) non-negative offset value.
*/
TimeList beginTimeList = super.getBegin();
if (beginTimeList.getLength() > 1) {
ArrayList<Time> singleTimeContainer = new ArrayList<Time>();
singleTimeContainer.add(beginTimeList.item(0));
beginTimeList = new TimeListImpl(singleTimeContainer);
}
return beginTimeList;
}
public NodeList getTimeChildren() {
return getChildNodes();
}
public boolean beginElement() {
DocumentEvent doc = (DocumentEvent) SmilParElementImpl.this.getOwnerDocument();
Event startEvent = doc.createEvent("Event");
startEvent.initEvent(SMIL_SLIDE_START_EVENT, false, false);
dispatchEvent(startEvent);
return true;
}
public boolean endElement() {
DocumentEvent doc = (DocumentEvent) SmilParElementImpl.this.getOwnerDocument();
Event endEvent = doc.createEvent("Event");
endEvent.initEvent(SMIL_SLIDE_END_EVENT, false, false);
dispatchEvent(endEvent);
return true;
}
public void pauseElement() {
// TODO Auto-generated method stub
}
public void resumeElement() {
// TODO Auto-generated method stub
}
public void seekElement(float seekTo) {
// TODO Auto-generated method stub
}
ElementTime getParentElementTime() {
return ((SmilDocumentImpl) mSmilElement.getOwnerDocument()).mSeqTimeContainer;
}
};
/*
* Internal Interface
*/
SmilParElementImpl(SmilDocumentImpl owner, String tagName)
{
super(owner, tagName.toUpperCase());
}
int getBeginConstraints() {
/*
* For children of a sequence, the only legal value for begin is
* a (single) non-negative offset value.
*/
return (TimeImpl.ALLOW_OFFSET_VALUE); // Do not set ALLOW_NEGATIVE_VALUE
}
/*
* ElementParallelTimeContainer
*/
public String getEndSync() {
return mParTimeContainer.getEndSync();
}
public float getImplicitDuration() {
return mParTimeContainer.getImplicitDuration();
}
public void setEndSync(String endSync) throws DOMException {
mParTimeContainer.setEndSync(endSync);
}
public NodeList getActiveChildrenAt(float instant) {
return mParTimeContainer.getActiveChildrenAt(instant);
}
public NodeList getTimeChildren() {
return mParTimeContainer.getTimeChildren();
}
public boolean beginElement() {
return mParTimeContainer.beginElement();
}
public boolean endElement() {
return mParTimeContainer.endElement();
}
public TimeList getBegin() {
return mParTimeContainer.getBegin();
}
public float getDur() {
return mParTimeContainer.getDur();
}
public TimeList getEnd() {
return mParTimeContainer.getEnd();
}
public short getFill() {
return mParTimeContainer.getFill();
}
public short getFillDefault() {
return mParTimeContainer.getFillDefault();
}
public float getRepeatCount() {
return mParTimeContainer.getRepeatCount();
}
public float getRepeatDur() {
return mParTimeContainer.getRepeatDur();
}
public short getRestart() {
return mParTimeContainer.getRestart();
}
public void pauseElement() {
mParTimeContainer.pauseElement();
}
public void resumeElement() {
mParTimeContainer.resumeElement();
}
public void seekElement(float seekTo) {
mParTimeContainer.seekElement(seekTo);
}
public void setBegin(TimeList begin) throws DOMException {
mParTimeContainer.setBegin(begin);
}
public void setDur(float dur) throws DOMException {
mParTimeContainer.setDur(dur);
}
public void setEnd(TimeList end) throws DOMException {
mParTimeContainer.setEnd(end);
}
public void setFill(short fill) throws DOMException {
mParTimeContainer.setFill(fill);
}
public void setFillDefault(short fillDefault) throws DOMException {
mParTimeContainer.setFillDefault(fillDefault);
}
public void setRepeatCount(float repeatCount) throws DOMException {
mParTimeContainer.setRepeatCount(repeatCount);
}
public void setRepeatDur(float repeatDur) throws DOMException {
mParTimeContainer.setRepeatDur(repeatDur);
}
public void setRestart(short restart) throws DOMException {
mParTimeContainer.setRestart(restart);
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.smil;
import org.w3c.dom.smil.SMILRefElement;
public class SmilRefElementImpl extends SmilRegionMediaElementImpl implements
SMILRefElement {
SmilRefElementImpl(SmilDocumentImpl owner, String tagName) {
super(owner, tagName);
}
}

View file

@ -0,0 +1,283 @@
/*
* 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 org.thoughtcrime.securesms.dom.smil;
import org.w3c.dom.DOMException;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILRegionElement;
import android.util.Log;
public class SmilRegionElementImpl extends SmilElementImpl implements
SMILRegionElement {
/*
* Internal Interface
*/
private static final String HIDDEN_ATTRIBUTE = "hidden";
private static final String SLICE_ATTRIBUTE = "slice";
private static final String SCROLL_ATTRIBUTE = "scroll";
private static final String MEET_ATTRIBUTE = "meet";
private static final String FILL_ATTRIBUTE = "fill";
private static final String ID_ATTRIBUTE_NAME = "id";
private static final String WIDTH_ATTRIBUTE_NAME = "width";
private static final String TITLE_ATTRIBUTE_NAME = "title";
private static final String HEIGHT_ATTRIBUTE_NAME = "height";
private static final String BACKGROUND_COLOR_ATTRIBUTE_NAME = "backgroundColor";
private static final String Z_INDEX_ATTRIBUTE_NAME = "z-index";
private static final String TOP_ATTRIBUTE_NAME = "top";
private static final String LEFT_ATTRIBUTE_NAME = "left";
private static final String RIGHT_ATTRIBUTE_NAME = "right";
private static final String BOTTOM_ATTRIBUTE_NAME = "bottom";
private static final String FIT_ATTRIBUTE_NAME = "fit";
private static final String TAG = "SmilRegionElementImpl";
private static final boolean DEBUG = false;
private static final boolean LOCAL_LOGV = false;
SmilRegionElementImpl(SmilDocumentImpl owner, String tagName) {
super(owner, tagName);
}
/*
* SMILRegionElement Interface
*/
public String getFit() {
String fit = getAttribute(FIT_ATTRIBUTE_NAME);
if (FILL_ATTRIBUTE.equalsIgnoreCase(fit)) {
return FILL_ATTRIBUTE;
} else if (MEET_ATTRIBUTE.equalsIgnoreCase(fit)) {
return MEET_ATTRIBUTE;
} else if (SCROLL_ATTRIBUTE.equalsIgnoreCase(fit)) {
return SCROLL_ATTRIBUTE;
} else if (SLICE_ATTRIBUTE.equalsIgnoreCase(fit)) {
return SLICE_ATTRIBUTE;
} else {
return HIDDEN_ATTRIBUTE;
}
}
public int getLeft() {
try {
return parseRegionLength(getAttribute(LEFT_ATTRIBUTE_NAME), true);
} catch (NumberFormatException _) {
if (LOCAL_LOGV) {
Log.v(TAG, "Left attribute is not set or incorrect.");
}
}
try {
int bbw = ((SMILDocument) getOwnerDocument()).getLayout().getRootLayout().getWidth();
int right = parseRegionLength(getAttribute(RIGHT_ATTRIBUTE_NAME), true);
int width = parseRegionLength(getAttribute(WIDTH_ATTRIBUTE_NAME), true);
return bbw - right - width;
} catch (NumberFormatException _) {
if (LOCAL_LOGV) {
Log.v(TAG, "Right or width attribute is not set or incorrect.");
}
}
return 0;
}
public int getTop() {
try {
return parseRegionLength(getAttribute(TOP_ATTRIBUTE_NAME), false);
} catch (NumberFormatException _) {
if (LOCAL_LOGV) {
Log.v(TAG, "Top attribute is not set or incorrect.");
}
}
try {
int bbh = ((SMILDocument) getOwnerDocument()).getLayout().getRootLayout().getHeight();
int bottom = parseRegionLength(getAttribute(BOTTOM_ATTRIBUTE_NAME), false);
int height = parseRegionLength(getAttribute(HEIGHT_ATTRIBUTE_NAME), false);
return bbh - bottom - height;
} catch (NumberFormatException _) {
if (LOCAL_LOGV) {
Log.v(TAG, "Bottom or height attribute is not set or incorrect.");
}
}
return 0;
}
public int getZIndex() {
try {
return Integer.parseInt(this.getAttribute(Z_INDEX_ATTRIBUTE_NAME));
} catch (NumberFormatException _) {
return 0;
}
}
public void setFit(String fit) throws DOMException {
if (fit.equalsIgnoreCase(FILL_ATTRIBUTE)
|| fit.equalsIgnoreCase(MEET_ATTRIBUTE)
|| fit.equalsIgnoreCase(SCROLL_ATTRIBUTE)
|| fit.equalsIgnoreCase(SLICE_ATTRIBUTE)) {
this.setAttribute(FIT_ATTRIBUTE_NAME, fit.toLowerCase());
} else {
this.setAttribute(FIT_ATTRIBUTE_NAME, HIDDEN_ATTRIBUTE);
}
}
public void setLeft(int left) throws DOMException {
this.setAttribute(LEFT_ATTRIBUTE_NAME, String.valueOf(left));
}
public void setTop(int top) throws DOMException {
this.setAttribute(TOP_ATTRIBUTE_NAME, String.valueOf(top));
}
public void setZIndex(int zIndex) throws DOMException {
if (zIndex > 0) {
this.setAttribute(Z_INDEX_ATTRIBUTE_NAME, Integer.toString(zIndex));
} else {
this.setAttribute(Z_INDEX_ATTRIBUTE_NAME, Integer.toString(0));
}
}
public String getBackgroundColor() {
return this.getAttribute(BACKGROUND_COLOR_ATTRIBUTE_NAME);
}
public int getHeight() {
try {
final int height = parseRegionLength(getAttribute(HEIGHT_ATTRIBUTE_NAME), false);
return height == 0 ?
((SMILDocument) getOwnerDocument()).getLayout().getRootLayout().getHeight() :
height;
} catch (NumberFormatException _) {
if (LOCAL_LOGV) {
Log.v(TAG, "Height attribute is not set or incorrect.");
}
}
int bbh = ((SMILDocument) getOwnerDocument()).getLayout().getRootLayout().getHeight();
try {
bbh -= parseRegionLength(getAttribute(TOP_ATTRIBUTE_NAME), false);
} catch (NumberFormatException _) {
if (LOCAL_LOGV) {
Log.v(TAG, "Top attribute is not set or incorrect.");
}
}
try {
bbh -= parseRegionLength(getAttribute(BOTTOM_ATTRIBUTE_NAME), false);
} catch (NumberFormatException _) {
if (LOCAL_LOGV) {
Log.v(TAG, "Bottom attribute is not set or incorrect.");
}
}
return bbh;
}
public String getTitle() {
return this.getAttribute(TITLE_ATTRIBUTE_NAME);
}
public int getWidth() {
try {
final int width = parseRegionLength(getAttribute(WIDTH_ATTRIBUTE_NAME), true);
return width == 0 ?
((SMILDocument) getOwnerDocument()).getLayout().getRootLayout().getWidth() :
width;
} catch (NumberFormatException _) {
if (LOCAL_LOGV) {
Log.v(TAG, "Width attribute is not set or incorrect.");
}
}
int bbw = ((SMILDocument) getOwnerDocument()).getLayout().getRootLayout().getWidth();
try {
bbw -= parseRegionLength(getAttribute(LEFT_ATTRIBUTE_NAME), true);
} catch (NumberFormatException _) {
if (LOCAL_LOGV) {
Log.v(TAG, "Left attribute is not set or incorrect.");
}
}
try {
bbw -= parseRegionLength(getAttribute(RIGHT_ATTRIBUTE_NAME), true);
} catch (NumberFormatException _) {
if (LOCAL_LOGV) {
Log.v(TAG, "Right attribute is not set or incorrect.");
}
}
return bbw;
}
public void setBackgroundColor(String backgroundColor) throws DOMException {
this.setAttribute(BACKGROUND_COLOR_ATTRIBUTE_NAME, backgroundColor);
}
public void setHeight(int height) throws DOMException {
this.setAttribute(HEIGHT_ATTRIBUTE_NAME, String.valueOf(height) + "px");
}
public void setTitle(String title) throws DOMException {
this.setAttribute(TITLE_ATTRIBUTE_NAME, title);
}
public void setWidth(int width) throws DOMException {
this.setAttribute(WIDTH_ATTRIBUTE_NAME, String.valueOf(width) + "px");
}
/*
* SMILElement Interface
*/
@Override
public String getId() {
return this.getAttribute(ID_ATTRIBUTE_NAME);
}
@Override
public void setId(String id) throws DOMException {
this.setAttribute(ID_ATTRIBUTE_NAME, id);
}
/*
* Internal Interface
*/
private int parseRegionLength(String length, boolean horizontal) {
if (length.endsWith("px")) {
length = length.substring(0, length.indexOf("px"));
return Integer.parseInt(length);
} else if (length.endsWith("%")) {
double value = 0.01*Integer.parseInt(length.substring(0, length.length() - 1));
if (horizontal) {
value *= ((SMILDocument) getOwnerDocument()).getLayout().getRootLayout().getWidth();
} else {
value *= ((SMILDocument) getOwnerDocument()).getLayout().getRootLayout().getHeight();
}
return (int) Math.round(value);
} else {
return Integer.parseInt(length);
}
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return super.toString()
+ ": id=" + getId()
+ ", width=" + getWidth()
+ ", height=" + getHeight()
+ ", left=" + getLeft()
+ ", top=" + getTop();
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.smil;
import org.w3c.dom.NodeList;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILRegionElement;
import org.w3c.dom.smil.SMILRegionMediaElement;
public class SmilRegionMediaElementImpl extends SmilMediaElementImpl implements
SMILRegionMediaElement {
private SMILRegionElement mRegion;
SmilRegionMediaElementImpl(SmilDocumentImpl owner, String tagName) {
super(owner, tagName);
}
public SMILRegionElement getRegion() {
if (mRegion == null) {
SMILDocument doc = (SMILDocument)this.getOwnerDocument();
NodeList regions = doc.getLayout().getElementsByTagName("region");
SMILRegionElement region = null;
for (int i = 0; i < regions.getLength(); i++) {
region = (SMILRegionElement)regions.item(i);
if (region.getId().equals(this.getAttribute("region"))) {
mRegion = region;
}
}
}
return mRegion;
}
public void setRegion(SMILRegionElement region) {
this.setAttribute("region", region.getId());
mRegion = region;
}
}

View file

@ -0,0 +1,84 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.smil;
import org.w3c.dom.DOMException;
import org.w3c.dom.smil.SMILRootLayoutElement;
public class SmilRootLayoutElementImpl extends SmilElementImpl implements
SMILRootLayoutElement {
private static final String WIDTH_ATTRIBUTE_NAME = "width";
private static final String HEIGHT_ATTRIBUTE_NAME = "height";
private static final String BACKGROUND_COLOR_ATTRIBUTE_NAME = "backgroundColor";
private static final String TITLE_ATTRIBUTE_NAME = "title";
SmilRootLayoutElementImpl(SmilDocumentImpl owner, String tagName) {
super(owner, tagName);
}
public String getBackgroundColor() {
return this.getAttribute(BACKGROUND_COLOR_ATTRIBUTE_NAME);
}
public int getHeight() {
String heightString = this.getAttribute(HEIGHT_ATTRIBUTE_NAME);
return parseAbsoluteLength(heightString);
}
public String getTitle() {
return this.getAttribute(TITLE_ATTRIBUTE_NAME);
}
public int getWidth() {
String widthString = this.getAttribute(WIDTH_ATTRIBUTE_NAME);
return parseAbsoluteLength(widthString);
}
public void setBackgroundColor(String backgroundColor) throws DOMException {
this.setAttribute(BACKGROUND_COLOR_ATTRIBUTE_NAME, backgroundColor);
}
public void setHeight(int height) throws DOMException {
this.setAttribute(HEIGHT_ATTRIBUTE_NAME, String.valueOf(height) + "px");
}
public void setTitle(String title) throws DOMException {
this.setAttribute(TITLE_ATTRIBUTE_NAME, title);
}
public void setWidth(int width) throws DOMException {
this.setAttribute(WIDTH_ATTRIBUTE_NAME, String.valueOf(width) + "px");
}
/*
* Internal Interface
*/
private int parseAbsoluteLength(String length) {
if (length.endsWith("px")) {
length = length.substring(0, length.indexOf("px"));
}
try {
return Integer.parseInt(length);
} catch (NumberFormatException e) {
return 0;
}
}
}

View file

@ -0,0 +1,295 @@
/*
* 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 org.thoughtcrime.securesms.dom.smil;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.smil.Time;
public class TimeImpl implements Time {
static final int ALLOW_INDEFINITE_VALUE = (1 << 0);
static final int ALLOW_OFFSET_VALUE = (1 << 1);
static final int ALLOW_SYNCBASE_VALUE = (1 << 2);
static final int ALLOW_SYNCTOPREV_VALUE = (1 << 3);
static final int ALLOW_EVENT_VALUE = (1 << 4);
static final int ALLOW_MARKER_VALUE = (1 << 5);
static final int ALLOW_WALLCLOCK_VALUE = (1 << 6);
static final int ALLOW_NEGATIVE_VALUE = (1 << 7);
static final int ALLOW_ALL = 0xFF;
short mTimeType;
boolean mResolved;
double mResolvedOffset;
/**
* Creates a TimeImpl representation of a time-value represented as a String.
* Time-values have the following syntax:
* <p>
* <pre>
* Time-val ::= ( smil-1.0-syncbase-value
* | "indefinite"
* | offset-value
* | syncbase-value
* | syncToPrev-value
* | event-value
* | media-marker-value
* | wallclock-sync-value )
* Smil-1.0-syncbase-value ::=
* "id(" id-ref ")" ( "(" ( "begin" | "end" | clock-value ) ")" )?
* Offset-value ::= ( "+" | "-" )? clock-value
* Syncbase-value ::= ( id-ref "." ( "begin" | "end" ) ) ( ( "+" | "-" ) clock-value )?
* SyncToPrev-value ::= ( "prev.begin" | "prev.end" ) ( ( "+" | "-" ) clock-value )?
* Event-value ::= ( id-ref "." )? ( event-ref ) ( ( "+" | "-" ) clock-value )?
* Media-marker-value ::= id-ref ".marker(" marker-name ")"
* Wallclock-sync-value ::= "wallclock(" wallclock-value ")"
* </pre>
*
* @param timeValue A String in the representation specified above
* @param constraints Any combination of the #ALLOW_* flags
* @return A TimeImpl instance representing
* @exception java.lang.IllegalArgumentException if the timeValue input
* parameter does not comply with the defined syntax
* @exception java.lang.NullPointerException if the timekValue string is
* <code>null</code>
*/
TimeImpl(String timeValue, int constraints) {
/*
* We do not support yet:
* - smil-1.0-syncbase-value
* - syncbase-value
* - syncToPrev-value
* - event-value
* - Media-marker-value
* - Wallclock-sync-value
*/
// Will throw NullPointerException if timeValue is null
if (timeValue.equals("indefinite")
&& ((constraints & ALLOW_INDEFINITE_VALUE) != 0) ) {
mTimeType = SMIL_TIME_INDEFINITE;
} else if ((constraints & ALLOW_OFFSET_VALUE) != 0) {
int sign = 1;
if (timeValue.startsWith("+")) {
timeValue = timeValue.substring(1);
} else if (timeValue.startsWith("-")) {
timeValue = timeValue.substring(1);
sign = -1;
}
mResolvedOffset = sign*parseClockValue(timeValue)/1000.0;
mResolved = true;
mTimeType = SMIL_TIME_OFFSET;
} else {
throw new IllegalArgumentException("Unsupported time value");
}
}
/**
* Converts a String representation of a clock value into the float
* representation used in this API.
* <p>
* Clock values have the following syntax:
* </p>
* <p>
* <pre>
* Clock-val ::= ( Full-clock-val | Partial-clock-val | Timecount-val )
* Full-clock-val ::= Hours ":" Minutes ":" Seconds ("." Fraction)?
* Partial-clock-val ::= Minutes ":" Seconds ("." Fraction)?
* Timecount-val ::= Timecount ("." Fraction)? (Metric)?
* Metric ::= "h" | "min" | "s" | "ms"
* Hours ::= DIGIT+; any positive number
* Minutes ::= 2DIGIT; range from 00 to 59
* Seconds ::= 2DIGIT; range from 00 to 59
* Fraction ::= DIGIT+
* Timecount ::= DIGIT+
* 2DIGIT ::= DIGIT DIGIT
* DIGIT ::= [0-9]
* </pre>
*
* @param clockValue A String in the representation specified above
* @return A float value in milliseconds that matches the string
* representation given as the parameter
* @exception java.lang.IllegalArgumentException if the clockValue input
* parameter does not comply with the defined syntax
* @exception java.lang.NullPointerException if the clockValue string is
* <code>null</code>
*/
public static float parseClockValue(String clockValue) {
try {
float result = 0;
// Will throw NullPointerException if clockValue is null
clockValue = clockValue.trim();
// Handle first 'Timecount-val' cases with metric
if (clockValue.endsWith("ms")) {
result = parseFloat(clockValue, 2, true);
} else if (clockValue.endsWith("s")) {
result = 1000*parseFloat(clockValue, 1, true);
} else if (clockValue.endsWith("min")) {
result = 60000*parseFloat(clockValue, 3, true);
} else if (clockValue.endsWith("h")) {
result = 3600000*parseFloat(clockValue, 1, true);
} else {
// Handle Timecount-val without metric
try {
return parseFloat(clockValue, 0, true) * 1000;
} catch (NumberFormatException _) {
// Ignore
}
// Split in {[Hours], Minutes, Seconds}
String[] timeValues = clockValue.split(":");
// Read Hours if present and remember location of Minutes
int indexOfMinutes;
if (timeValues.length == 2) {
indexOfMinutes = 0;
} else if (timeValues.length == 3) {
result = 3600000*(int)parseFloat(timeValues[0], 0, false);
indexOfMinutes = 1;
} else {
throw new IllegalArgumentException();
}
// Read Minutes
int minutes = (int)parseFloat(timeValues[indexOfMinutes], 0, false);
if ((minutes >= 00) && (minutes <= 59)) {
result += 60000*minutes;
} else {
throw new IllegalArgumentException();
}
// Read Seconds
float seconds = parseFloat(timeValues[indexOfMinutes + 1], 0, true);
if ((seconds >= 00) && (seconds < 60)) {
result += 60000*seconds;
} else {
throw new IllegalArgumentException();
}
}
return result;
} catch (NumberFormatException e) {
throw new IllegalArgumentException();
}
}
/**
* Parse a value formatted as follows:
* <p>
* <pre>
* Value ::= Number ("." Decimal)? (Text)?
* Number ::= DIGIT+; any positive number
* Decimal ::= DIGIT+; any positive number
* Text ::= CHAR*; any sequence of chars
* DIGIT ::= [0-9]
* </pre>
* @param value The Value to parse
* @param ignoreLast The size of Text to ignore
* @param parseDecimal Whether Decimal is expected
* @return The float value without Text, rounded to 3 digits after '.'
* @throws IllegalArgumentException if Decimal was not expected but encountered
*/
private static float parseFloat(String value, int ignoreLast, boolean parseDecimal) {
// Ignore last characters
value = value.substring(0, value.length() - ignoreLast);
float result;
int indexOfComma = value.indexOf('.');
if (indexOfComma != -1) {
if (!parseDecimal) {
throw new IllegalArgumentException("int value contains decimal");
}
// Ensure that there are at least 3 decimals
value = value + "000";
// Read value up to 3 decimals and cut the rest
result = Float.parseFloat(value.substring(0, indexOfComma));
result += Float.parseFloat(
value.substring(indexOfComma + 1, indexOfComma + 4))/1000;
} else {
result = Integer.parseInt(value);
}
return result;
}
/*
* Time Interface
*/
public boolean getBaseBegin() {
// TODO Auto-generated method stub
return false;
}
public Element getBaseElement() {
// TODO Auto-generated method stub
return null;
}
public String getEvent() {
// TODO Auto-generated method stub
return null;
}
public String getMarker() {
// TODO Auto-generated method stub
return null;
}
public double getOffset() {
// TODO Auto-generated method stub
return 0;
}
public boolean getResolved() {
return mResolved;
}
public double getResolvedOffset() {
return mResolvedOffset;
}
public short getTimeType() {
return mTimeType;
}
public void setBaseBegin(boolean baseBegin) throws DOMException {
// TODO Auto-generated method stub
}
public void setBaseElement(Element baseElement) throws DOMException {
// TODO Auto-generated method stub
}
public void setEvent(String event) throws DOMException {
// TODO Auto-generated method stub
}
public void setMarker(String marker) throws DOMException {
// TODO Auto-generated method stub
}
public void setOffset(double offset) throws DOMException {
// TODO Auto-generated method stub
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.smil;
import java.util.ArrayList;
import org.w3c.dom.smil.Time;
import org.w3c.dom.smil.TimeList;
public class TimeListImpl implements TimeList {
private final ArrayList<Time> mTimes;
/*
* Internal Interface
*/
TimeListImpl(ArrayList<Time> times) {
mTimes = times;
}
/*
* TimeList Interface
*/
public int getLength() {
return mTimes.size();
}
public Time item(int index) {
Time time = null;
try {
time = mTimes.get(index);
} catch (IndexOutOfBoundsException e) {
// Do nothing and return null
}
return time;
}
}

View file

@ -0,0 +1,80 @@
/*
* Copyright (C) 2007 Esmertec AG.
* Copyright (C) 2007 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 org.thoughtcrime.securesms.dom.smil.parser;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILElement;
public class SmilXmlSerializer {
public static void serialize(SMILDocument smilDoc, OutputStream out) {
try {
Writer writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"), 2048);
writeElement(writer, smilDoc.getDocumentElement());
writer.flush();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void writeElement(Writer writer, Element element)
throws IOException {
writer.write('<');
writer.write(element.getTagName());
if (element.hasAttributes()) {
NamedNodeMap attributes = element.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Attr attribute = (Attr)attributes.item(i);
writer.write(" " + attribute.getName());
writer.write("=\"" + attribute.getValue() + "\"");
}
}
// FIXME: Might throw ClassCastException
SMILElement childElement = (SMILElement) element.getFirstChild();
if (childElement != null) {
writer.write('>');
do {
writeElement(writer, childElement);
childElement = (SMILElement) childElement.getNextSibling();
} while (childElement != null);
writer.write("</");
writer.write(element.getTagName());
writer.write('>');
} else {
writer.write("/>");
}
}
}

View file

@ -19,16 +19,18 @@ package org.thoughtcrime.securesms.mms;
import java.io.IOException;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.SmilUtil;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.SMILRegionElement;
import org.w3c.dom.smil.SMILRegionMediaElement;
import ws.com.google.android.mms.pdu.PduPart;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.MediaStore.Audio;
import android.widget.ImageView;
public class AudioSlide extends Slide {
@ -49,7 +51,17 @@ public class AudioSlide extends Slide {
public boolean hasAudio() {
return true;
}
@Override
public SMILRegionElement getSmilRegion(SMILDocument document) {
return null;
}
@Override
public SMILMediaElement getMediaElement(SMILDocument document) {
return SmilUtil.createMediaElement("audio", document, new String(getPart().getName()));
}
@Override
public Drawable getThumbnail(int maxWidth, int maxHeight) {
return context.getResources().getDrawable(R.drawable.ic_menu_add_sound);
@ -81,5 +93,4 @@ public class AudioSlide extends Slide {
return part;
}
}

View file

@ -33,6 +33,10 @@ import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.LRUCache;
import org.thoughtcrime.securesms.util.SmilUtil;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.SMILRegionElement;
import org.whispersystems.textsecure.crypto.MasterSecret;
import java.io.FileNotFoundException;
@ -59,7 +63,7 @@ public class ImageSlide extends Slide {
public ImageSlide(Context context, Uri uri) throws IOException, BitmapDecodingException {
super(context, constructPartFromUri(context, uri));
}
@Override
public Drawable getThumbnail(int maxWidth, int maxHeight) {
Drawable thumbnail = getCachedThumbnail();
@ -161,12 +165,29 @@ public class ImageSlide extends Slide {
public boolean hasImage() {
return true;
}
@Override
public SMILRegionElement getSmilRegion(SMILDocument document) {
SMILRegionElement region = (SMILRegionElement) document.createElement("region");
region.setId("Image");
region.setLeft(0);
region.setTop(0);
region.setWidth(SmilUtil.ROOT_WIDTH);
region.setHeight(SmilUtil.ROOT_HEIGHT);
region.setFit("meet");
return region;
}
@Override
public SMILMediaElement getMediaElement(SMILDocument document) {
return SmilUtil.createMediaElement("img", document, new String(getPart().getName()));
}
private static PduPart constructPartFromUri(Context context, Uri uri)
throws IOException, BitmapDecodingException
{
PduPart part = new PduPart();
byte[] data = BitmapUtil.createScaledBytes(context, uri, 640, 480, (300 * 1024) - 5000);
byte[] data = BitmapUtil.createScaledBytes(context, uri, 1280, 1280, MAX_MESSAGE_SIZE);
part.setData(data);
part.setDataUri(uri);

View file

@ -20,6 +20,9 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.SMILRegionElement;
import org.whispersystems.textsecure.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.providers.PartProvider;
@ -36,61 +39,61 @@ import ws.com.google.android.mms.pdu.PduPart;
public abstract class Slide {
protected static final int MAX_MESSAGE_SIZE = 1048576;
protected static final int MAX_MESSAGE_SIZE = 280 * 1024;
protected final PduPart part;
protected final Context context;
protected MasterSecret masterSecret;
public Slide(Context context, PduPart part) {
this.part = part;
this.context = context;
}
public Slide(Context context, MasterSecret masterSecret, PduPart part) {
this(context, part);
this.masterSecret = masterSecret;
}
public InputStream getPartDataInputStream() throws FileNotFoundException {
Uri partUri = part.getDataUri();
Log.w("Slide", "Loading Part URI: " + partUri);
if (PartProvider.isAuthority(partUri))
return DatabaseFactory.getEncryptingPartDatabase(context, masterSecret).getPartStream(ContentUris.parseId(partUri));
else
return context.getContentResolver().openInputStream(partUri);
}
protected static long getMediaSize(Context context, Uri uri) throws IOException {
InputStream in = context.getContentResolver().openInputStream(uri);
long size = 0;
long size = 0;
byte[] buffer = new byte[512];
int read;
while ((read = in.read(buffer)) != -1)
size += read;
return size;
}
protected byte[] getPartData() {
if (part.getData() != null)
return part.getData();
long partId = ContentUris.parseId(part.getDataUri());
return DatabaseFactory.getEncryptingPartDatabase(context, masterSecret).getPart(partId, true).getData();
}
public String getContentType() {
return new String(part.getContentType());
}
public Uri getUri() {
return part.getDataUri();
}
public Drawable getThumbnail(int maxWidth, int maxHeight) {
throw new AssertionError("getThumbnail() called on non-thumbnail producing slide!");
}
@ -102,28 +105,32 @@ public abstract class Slide {
public boolean hasImage() {
return false;
}
public boolean hasVideo() {
return false;
}
public boolean hasAudio() {
return false;
}
public Bitmap getImage() {
throw new AssertionError("getImage() called on non-image slide!");
}
public boolean hasText() {
return false;
}
public String getText() {
throw new AssertionError("getText() called on non-text slide!");
}
public PduPart getPart() {
return part;
}
public abstract SMILRegionElement getSmilRegion(SMILDocument document);
public abstract SMILMediaElement getMediaElement(SMILDocument document);
}

View file

@ -18,8 +18,11 @@ package org.thoughtcrime.securesms.mms;
import android.content.Context;
import org.thoughtcrime.securesms.dom.smil.parser.SmilXmlSerializer;
import org.thoughtcrime.securesms.util.SmilUtil;
import org.whispersystems.textsecure.crypto.MasterSecret;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;
@ -27,9 +30,9 @@ import java.util.List;
import ws.com.google.android.mms.ContentType;
import ws.com.google.android.mms.pdu.CharacterSets;
import ws.com.google.android.mms.pdu.PduBody;
import ws.com.google.android.mms.pdu.PduPart;
public class SlideDeck {
private final List<Slide> slides = new LinkedList<Slide>();
public SlideDeck(Context context, MasterSecret masterSecret, PduBody body) {
@ -44,7 +47,7 @@ public class SlideDeck {
slides.add(new AudioSlide(context, body.getPart(i)));
else if (ContentType.isTextType(contentType))
slides.add(new TextSlide(context, masterSecret, body.getPart(i)));
}
}
} catch (UnsupportedEncodingException uee) {
throw new AssertionError(uee);
}
@ -52,7 +55,7 @@ public class SlideDeck {
public SlideDeck() {
}
public void clear() {
slides.clear();
}
@ -63,7 +66,16 @@ public class SlideDeck {
for (Slide slide : slides) {
body.addPart(slide.getPart());
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
SmilXmlSerializer.serialize(SmilUtil.createSmilDocument(this), out);
PduPart smilPart = new PduPart();
smilPart.setContentId("smil".getBytes());
smilPart.setContentLocation("smil.xml".getBytes());
smilPart.setContentType(ContentType.APP_SMIL.getBytes());
smilPart.setData(out.toByteArray());
body.addPart(0, smilPart);
return body;
}

View file

@ -20,6 +20,10 @@ import android.content.Context;
import android.net.Uri;
import android.util.Log;
import org.thoughtcrime.securesms.util.SmilUtil;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.SMILRegionElement;
import org.whispersystems.textsecure.crypto.MasterSecret;
import org.thoughtcrime.securesms.util.LRUCache;
@ -74,7 +78,24 @@ public class TextSlide extends Slide {
return new String(getPartData());
}
}
@Override
public SMILRegionElement getSmilRegion(SMILDocument document) {
SMILRegionElement region = (SMILRegionElement) document.createElement("region");
region.setId("Text");
region.setLeft(0);
region.setTop(SmilUtil.ROOT_HEIGHT);
region.setWidth(SmilUtil.ROOT_WIDTH);
region.setHeight(50);
region.setFit("meet");
return region;
}
@Override
public SMILMediaElement getMediaElement(SMILDocument document) {
return SmilUtil.createMediaElement("text", document, new String(getPart().getName()));
}
private static PduPart getPartForMessage(String message) {
PduPart part = new PduPart();

View file

@ -19,18 +19,19 @@ package org.thoughtcrime.securesms.mms;
import java.io.IOException;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.SmilUtil;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.SMILRegionElement;
import ws.com.google.android.mms.pdu.PduPart;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.ImageView;
public class VideoSlide extends Slide {
@ -41,7 +42,7 @@ public class VideoSlide extends Slide {
public VideoSlide(Context context, Uri uri) throws IOException, MediaTooLargeException {
super(context, constructPartFromUri(context, uri));
}
@Override
public Drawable getThumbnail(int width, int height) {
return context.getResources().getDrawable(R.drawable.ic_launcher_video_player);
@ -51,12 +52,29 @@ public class VideoSlide extends Slide {
public boolean hasImage() {
return true;
}
@Override
public boolean hasVideo() {
return true;
}
@Override
public SMILRegionElement getSmilRegion(SMILDocument document) {
SMILRegionElement region = (SMILRegionElement) document.createElement("region");
region.setId("Image");
region.setLeft(0);
region.setTop(0);
region.setWidth(SmilUtil.ROOT_WIDTH);
region.setHeight(SmilUtil.ROOT_HEIGHT);
region.setFit("meet");
return region;
}
@Override
public SMILMediaElement getMediaElement(SMILDocument document) {
return SmilUtil.createMediaElement("video", document, new String(getPart().getName()));
}
private static PduPart constructPartFromUri(Context context, Uri uri) throws IOException, MediaTooLargeException {
PduPart part = new PduPart();
ContentResolver resolver = context.getContentResolver();

View file

@ -0,0 +1,75 @@
package org.thoughtcrime.securesms.util;
import android.util.Log;
import org.thoughtcrime.securesms.dom.smil.SmilDocumentImpl;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.w3c.dom.smil.SMILDocument;
import org.w3c.dom.smil.SMILElement;
import org.w3c.dom.smil.SMILLayoutElement;
import org.w3c.dom.smil.SMILMediaElement;
import org.w3c.dom.smil.SMILParElement;
import org.w3c.dom.smil.SMILRegionElement;
import org.w3c.dom.smil.SMILRegionMediaElement;
import org.w3c.dom.smil.SMILRootLayoutElement;
public class SmilUtil {
private static final String TAG = SmilUtil.class.getSimpleName();
public static final int ROOT_HEIGHT = 1024;
public static final int ROOT_WIDTH = 1024;
public static SMILDocument createSmilDocument(SlideDeck deck) {
Log.w(TAG, "Creating SMIL document from SlideDeck.");
SMILDocument document = new SmilDocumentImpl();
SMILElement smilElement = (SMILElement) document.createElement("smil");
document.appendChild(smilElement);
SMILElement headElement = (SMILElement) document.createElement("head");
smilElement.appendChild(headElement);
SMILLayoutElement layoutElement = (SMILLayoutElement) document.createElement("layout");
headElement.appendChild(layoutElement);
SMILRootLayoutElement rootLayoutElement = (SMILRootLayoutElement) document.createElement("root-layout");
rootLayoutElement.setWidth(ROOT_WIDTH);
rootLayoutElement.setHeight(ROOT_HEIGHT);
layoutElement.appendChild(rootLayoutElement);
SMILElement bodyElement = (SMILElement) document.createElement("body");
smilElement.appendChild(bodyElement);
SMILParElement par = (SMILParElement) document.createElement("par");
bodyElement.appendChild(par);
for (Slide slide : deck.getSlides()) {
SMILRegionElement regionElement = slide.getSmilRegion(document);
SMILMediaElement mediaElement = slide.getMediaElement(document);
if (regionElement != null) {
((SMILRegionMediaElement)mediaElement).setRegion(regionElement);
layoutElement.appendChild(regionElement);
}
par.appendChild(mediaElement);
}
return document;
}
public static SMILMediaElement createMediaElement(String tag, SMILDocument document, String src) {
SMILMediaElement mediaElement = (SMILMediaElement) document.createElement(tag);
mediaElement.setSrc(escapeXML(src));
return mediaElement;
}
private static String escapeXML(String str) {
return str.replaceAll("&","&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll("\"", "&quot;")
.replaceAll("'", "&apos;");
}
}