Return-Path: X-Original-To: apmail-incubator-callback-commits-archive@minotaur.apache.org Delivered-To: apmail-incubator-callback-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id ED19A9342 for ; Wed, 8 Feb 2012 20:15:22 +0000 (UTC) Received: (qmail 47677 invoked by uid 500); 8 Feb 2012 20:15:22 -0000 Delivered-To: apmail-incubator-callback-commits-archive@incubator.apache.org Received: (qmail 47658 invoked by uid 500); 8 Feb 2012 20:15:22 -0000 Mailing-List: contact callback-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: callback-dev@incubator.apache.org Delivered-To: mailing list callback-commits@incubator.apache.org Received: (qmail 47651 invoked by uid 99); 8 Feb 2012 20:15:22 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Feb 2012 20:15:22 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.114] (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Feb 2012 20:14:57 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 5120D31D5F2; Wed, 8 Feb 2012 20:14:02 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: deedubbu@apache.org To: callback-commits@incubator.apache.org X-Mailer: ASF-Git Admin Mailer Subject: [15/19] CB-226 Rename to Cordova. Message-Id: <20120208201402.5120D31D5F2@tyr.zones.apache.org> Date: Wed, 8 Feb 2012 20:14:02 +0000 (UTC) X-Virus-Checked: Checked by ClamAV on apache.org http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JStringReader.java ---------------------------------------------------------------------- diff --git a/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JStringReader.java b/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JStringReader.java new file mode 100644 index 0000000..5c3583a --- /dev/null +++ b/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JStringReader.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cordova.json4j.internal; + +import java.io.IOException; +import java.io.Reader; + +public class JSON4JStringReader extends Reader { + + private char[] _buf = null; + private int _mark = 0; + private int maxLength = 0; + + public JSON4JStringReader(String str) { + _buf = str.toCharArray(); + maxLength = str.length(); + _mark = 0; + } + + public void close() throws IOException { + return; + } + + public int read(char[] cbuf, int off, int len) throws IOException { + if (_mark == (maxLength)) + return -1; + + int read = 0; + for (int x=0; x= _buffer.length) { + // Resize the array first. + _buffer = JSON4JStringWriter.resizeArray(_buffer); + } + for (int x=0; x < len; x++) { + _buffer[_mark] = cbuf[off+x]; + _mark++; + } + } + + public String toString() { + return new String(_buffer, 0, _mark); + } +} http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/json4j/internal/NumberUtil.java ---------------------------------------------------------------------- diff --git a/framework/ext/src/org/apache/cordova/json4j/internal/NumberUtil.java b/framework/ext/src/org/apache/cordova/json4j/internal/NumberUtil.java new file mode 100644 index 0000000..d63d4db --- /dev/null +++ b/framework/ext/src/org/apache/cordova/json4j/internal/NumberUtil.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cordova.json4j.internal; + +public class NumberUtil { + + public static boolean isNumber(Class clazz) { + if ( (clazz == Integer.class) || (clazz == Long.class) || (clazz == Double.class) || (clazz == Short.class) || (clazz == Float.class)) { + return true; + } + return false; + } + + public static double getDouble(Object val) { + if (val instanceof Double) { + return ((Double)val).doubleValue(); + } + else if (val instanceof Long) { + return ((Long)val).doubleValue(); + } + else if (val instanceof Short) { + Integer i = new Integer( ((Short)val).shortValue() ); + return i.doubleValue(); + } + else if (val instanceof Float) { + return ((Float)val).doubleValue(); + } + else if (val instanceof Integer) { + return ((Integer)val).doubleValue(); + } + throw new IllegalArgumentException("Not a number"); + } + + public static short getShort(Object val) { + if (val instanceof Double) { + return ((Double)val).shortValue(); + } + else if (val instanceof Long) { + Double dg = new Double(((Long)val).longValue()); + return dg.shortValue(); + } + else if (val instanceof Short) { + return ((Short)val).shortValue(); + } + else if (val instanceof Float) { + return ((Float)val).shortValue(); + } else if (val instanceof Integer) { + return ((Integer)val).shortValue(); + } + throw new IllegalArgumentException("Not a number"); + } + + public static int getInt(Object val) { + if (val instanceof Double) { + return ((Double)val).intValue(); + } + else if (val instanceof Long) { + Double dg = new Double(((Long)val).longValue()); + return dg.intValue(); + } + else if (val instanceof Short) { + Double dg = new Double(((Short)val).shortValue()); + return dg.intValue(); + } + else if (val instanceof Float) { + return ((Float)val).intValue(); + } + else if (val instanceof Integer) { + return ((Integer)val).intValue(); + } + throw new IllegalArgumentException("Not a number"); + } + + public static long getLong(Object val) { + if (val instanceof Double) { + return ((Double)val).longValue(); + } + else if (val instanceof Long) { + return ((Long)val).longValue(); + } + else if (val instanceof Short) { + Long lg = new Long(((Short)val).shortValue()); + return lg.longValue(); + } + else if (val instanceof Float) { + return ((Float)val).longValue(); + } + else if (val instanceof Integer) { + return ((Integer)val).longValue(); + } + throw new IllegalArgumentException("Not a number"); + } +} http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/json4j/internal/Parser.java ---------------------------------------------------------------------- diff --git a/framework/ext/src/org/apache/cordova/json4j/internal/Parser.java b/framework/ext/src/org/apache/cordova/json4j/internal/Parser.java new file mode 100644 index 0000000..39ddf98 --- /dev/null +++ b/framework/ext/src/org/apache/cordova/json4j/internal/Parser.java @@ -0,0 +1,338 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cordova.json4j.internal; + +import java.io.IOException; +import java.io.Reader; + +import org.apache.cordova.json4j.JSONArray; +import org.apache.cordova.json4j.JSONException; +import org.apache.cordova.json4j.JSONObject; + +/** + * Private parser class which handles doing the parsing of the JSON string into tokens. + */ +public class Parser { + + private Tokenizer tokenizer; + private Token lastToken; + + /** + * Contructor + * @param reader The Reader to use when reading in the JSON stream/string. + * + * @throws JSONException Thrown if an error occurs in tokenizing the JSON string. + */ + public Parser(Reader reader) throws JSONException { + super(); + try { + this.tokenizer = new Tokenizer(reader, false); + } catch (IOException iox) { + JSONException jex = new JSONException("Error occurred during input read."); + jex.setCause(iox); + throw jex; + } + } + + /** + * Contructor + * @param reader The Reader to use when reading in the JSON stream/string. + * @param strict Boolean indicating if the parser should parse in strict mode, meaning unqoted strings and comments are not allowed. + * + * @throws JSONException Thrown if an error occurs in tokenizing the JSON string. + */ + public Parser(Reader reader, boolean strict) throws JSONException { + super(); + try { + this.tokenizer = new Tokenizer(reader, strict); + } catch (IOException iox) { + JSONException jex = new JSONException("Error occurred during input read."); + jex.setCause(iox); + throw jex; + } + } + + /** + * Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within. + * Same as calling parse(false); + * + * @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s). + */ + public JSONObject parse() throws JSONException { + return parse(false, (JSONObject)null); + } + + /** + * Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within. + * Same as calling parse(false); + * + * @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s). + */ + public JSONObject parse(JSONObject jObj) throws JSONException { + return parse(false, jObj); + } + + /** + * Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within. + * @param ordered Flag to denote if the parse should contruct a JSON object which maintains serialization order of the attributes. + * + * @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s). + */ + public JSONObject parse(boolean ordered) throws JSONException { + try { + lastToken = tokenizer.next(); + } catch (IOException iox) { + JSONException jex = new JSONException("Error occurred during input read."); + jex.setCause(iox); + throw jex; + } + return parseObject(ordered, null); + } + + /** + * Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within. + * @param ordered Flag to denote if the parse should contruct a JSON object which maintains serialization order of the attributes. + * @param jObj The JSONObjetc to fill out from the parsing. If null, create a new one. + * + * @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s). + */ + public JSONObject parse(boolean ordered, JSONObject jObj) throws JSONException { + try { + lastToken = tokenizer.next(); + } catch (IOException iox) { + JSONException jex = new JSONException("Error occurred during input read."); + jex.setCause(iox); + throw jex; + } + return parseObject(ordered, jObj); + } + + /** + * Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within. + * @param jObj The JSONArray to fill out from the parsing. If null, create a new one. + * + * @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s). + */ + public JSONArray parse(JSONArray jObj) throws JSONException { + return parse(false, jObj); + } + + /** + * Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within. + * @param ordered Flag to denote if the parse should contruct for all JSON objects encounted, a JSON object which maintains serialization order of the attributes. + * @param jObj The JSONArray to fill out from the parsing. If null, create a new one. + * + * @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s). + */ + public JSONArray parse(boolean ordered, JSONArray jObj) throws JSONException { + try { + lastToken = tokenizer.next(); + } catch (IOException iox) { + JSONException jex = new JSONException("Error occurred during input read."); + jex.setCause(iox); + throw jex; + } + return parseArray(ordered, jObj); + } + + /** + * Method to parse a JSON object out of the current JSON string position. + * @return JSONObject Returns the parsed out JSON object. + * + * @throws JSONException Thrown if an IO error occurs during parse, such as a malformed JSON object. + */ + public JSONObject parseObject() throws JSONException { + return parseObject(false, null); + } + + /** + * Method to parse a JSON object out of the current JSON string position. + * @param ordered Flag to denote if the parse should contruct a JSON object which maintains serialization order of the attributes. + * @return JSONObject Returns the parsed out JSON object. + * + * @throws JSONException Thrown if an IO error occurs during parse, such as a malformed JSON object. + */ + public JSONObject parseObject(boolean ordered, JSONObject rootObject) throws JSONException { + + try { + JSONObject result = null; + if (rootObject != null) { + result = rootObject; + } else { + if (!ordered) { + result = new JSONObject(); + } else { + //MSN NO ORDERED + result = new JSONObject(); + } + } + + if (lastToken != Token.TokenBraceL) throw new JSONException("Expecting '{' " + tokenizer.onLineCol() + " instead, obtained token: '" + lastToken + "'"); + lastToken = tokenizer.next(); + + while (true) { + if (lastToken == Token.TokenEOF) throw new JSONException("Unterminated object " + tokenizer.onLineCol()); + + if (lastToken == Token.TokenBraceR) { + lastToken = tokenizer.next(); + break; + } + + if (!lastToken.isString()) throw new JSONException("Expecting string key " + tokenizer.onLineCol()); + String key = lastToken.getString(); + + lastToken = tokenizer.next(); + if (lastToken != Token.TokenColon) throw new JSONException("Expecting colon " + tokenizer.onLineCol()); + + lastToken = tokenizer.next(); + Object val = parseValue(ordered); + + result.put(key, val); + + if (lastToken == Token.TokenComma) { + lastToken = tokenizer.next(); + } + + else if (lastToken != Token.TokenBraceR) { + throw new JSONException("expecting either ',' or '}' " + tokenizer.onLineCol()); + } + } + return result; + } catch (IOException iox) { + JSONException jex = new JSONException("Error occurred during object input read."); + jex.setCause(iox); + throw jex; + } + } + + /** + * Method to parse out a JSON array from a JSON string + * Same as calling parseArray(false, null) + * + * @throws JSONException Thrown if a parse error occurs, such as a malformed JSON array. + */ + public JSONArray parseArray() throws JSONException { + return parseArray(false, null); + } + + /** + * Method to parse out a JSON array from a JSON string + * @param ordered Flag to denote if the parse should contruct JSON objects which maintain serialization order of the attributes for all JSONOjects in the array. + * *param array An array instance to populate instead of creating a new one. + * + * @throws JSONException Thrown if a parse error occurs, such as a malformed JSON array. + */ + public JSONArray parseArray(boolean ordered, JSONArray array) throws JSONException { + JSONArray result = null; + if(array != null){ + result = array; + } else { + result = new JSONArray(); + } + + try { + if (lastToken != Token.TokenBrackL) throw new JSONException("Expecting '[' " + tokenizer.onLineCol()); + lastToken = tokenizer.next(); + while (true) { + if (lastToken == Token.TokenEOF) throw new JSONException("Unterminated array " + tokenizer.onLineCol()); + + /** + * End of the array. + */ + if (lastToken == Token.TokenBrackR) { + lastToken = tokenizer.next(); + break; + } + + Object val = parseValue(ordered); + result.add(val); + + if (lastToken == Token.TokenComma) { + lastToken = tokenizer.next(); + } else if (lastToken != Token.TokenBrackR) { + throw new JSONException("expecting either ',' or ']' " + tokenizer.onLineCol()); + } + } + } catch (IOException iox) { + JSONException jex = new JSONException("Error occurred during array input read."); + jex.setCause(iox); + throw jex; + } + return result; + } + + /** + * Method to parse the current JSON property value from the last token. + * @return The java object type that represents the JSON value. + * + * @throws JSONException Thrown if an IO error (read incomplete token) occurs. + */ + public Object parseValue() throws JSONException { + return parseValue(false); + } + + /** + * Method to parse the current JSON property value from the last token. + * @return The java object type that represents the JSON value. + * @param ordered Flag to denote if the parse should contruct JSON objects and arrays which maintain serialization order of the attributes. + * + * @throws JSONException Thrown if an IO error (read incomplete token) occurs. + */ + public Object parseValue(boolean ordered) throws JSONException { + if (lastToken == Token.TokenEOF) throw new JSONException("Expecting property value " + tokenizer.onLineCol()); + + try { + if (lastToken.isNumber()) { + Object result = lastToken.getNumber(); + lastToken = tokenizer.next(); + return result; + } + + if (lastToken.isString()) { + Object result = lastToken.getString(); + lastToken = tokenizer.next(); + return result; + } + + if (lastToken == Token.TokenFalse) { + lastToken = tokenizer.next(); + return Boolean.FALSE; + } + + if (lastToken == Token.TokenTrue) { + lastToken = tokenizer.next(); + return Boolean.TRUE; + } + + if (lastToken == Token.TokenNull) { + lastToken = tokenizer.next(); + return JSONObject.NULL; + } + + if (lastToken == Token.TokenBrackL) return parseArray(ordered, null); + if (lastToken == Token.TokenBraceL) return parseObject(ordered, null); + + } catch (IOException iox) { + JSONException jex = new JSONException("Error occurred during value input read."); + jex.setCause(iox); + throw jex; + } + throw new JSONException("Invalid token " + tokenizer.onLineCol()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/json4j/internal/Serializer.java ---------------------------------------------------------------------- diff --git a/framework/ext/src/org/apache/cordova/json4j/internal/Serializer.java b/framework/ext/src/org/apache/cordova/json4j/internal/Serializer.java new file mode 100644 index 0000000..50f34d3 --- /dev/null +++ b/framework/ext/src/org/apache/cordova/json4j/internal/Serializer.java @@ -0,0 +1,353 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cordova.json4j.internal; + +import java.io.IOException; +import java.io.Writer; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.apache.cordova.json4j.JSONArray; +import org.apache.cordova.json4j.JSONObject; +import org.apache.cordova.json4j.JSONString; + +/** + * Class to handle serialization of a JSON object to a JSON string. + */ +public class Serializer { + + /** + * The writer to use when writing this JSON object. + */ + private Writer writer; + + /** + * Create a serializer on the specified output stream writer. + */ + public Serializer(Writer writer) { + super(); + this.writer = writer; + } + + /** + * Method to flush the current writer. + * @throws IOException Thrown if an error occurs during writer flush. + */ + public void flush() throws IOException { + writer.flush(); + } + + /** + * Method to close the current writer. + * @throws IOException Thrown if an error occurs during writer close. + */ + public void close() throws IOException { + writer.close(); + } + + /** + * Method to write a raw string to the writer. + * @param s The String to write. + * @throws IOException Thrown if an error occurs during write. + */ + public Serializer writeRawString(String s) throws IOException { + writer.write(s); + return this; + } + + /** + * Method to write the text string 'null' to the output stream (null JSON object). + * @throws IOException Thrown if an error occurs during write. + */ + public Serializer writeNull() throws IOException { + writeRawString("null"); + return this; + } + + /** + * Method to write a number to the current writer. + * @param value The number to write to the JSON output string. + * @throws IOException Thrown if an error occurs during write. + */ + public Serializer writeNumber(Object value) throws IOException { + if (null == value) return writeNull(); + + if (value instanceof Float) { + if (((Float)value).isNaN()) return writeNull(); + if (Float.NEGATIVE_INFINITY == ((Float)value).floatValue()) return writeNull(); + if (Float.POSITIVE_INFINITY == ((Float)value).floatValue()) return writeNull(); + } + + if (value instanceof Double) { + if (((Double)value).isNaN()) return writeNull(); + if (Double.NEGATIVE_INFINITY == ((Double)value).doubleValue()) return writeNull(); + if (Double.POSITIVE_INFINITY == ((Double)value).doubleValue()) return writeNull(); + } + + writeRawString(value.toString()); + + return this; + } + + /** + * Method to write a boolean value to the output stream. + * @param value The Boolean object to write out as a JSON boolean. + * @throws IOException Thrown if an error occurs during write. + */ + public Serializer writeBoolean(Boolean value) throws IOException { + if (null == value) return writeNull(); + + writeRawString(value.toString()); + + return this; + } + + /** + * Method to generate a string with a particular width. Alignment is done using zeroes if it does not meet the width requirements. + * @param s The string to write + * @param len The minimum length it should be, and to align with zeroes if length is smaller. + * @return A string properly aligned/correct width. + */ + private static String rightAlignedZero(String s, int len) { + if (len == s.length()) return s; + + StringBuffer sb = new StringBuffer(s); + + while (sb.length() < len) { + sb.insert(0, '0'); + } + + return sb.toString(); + } + + /** + * Method to write a String out to the writer, encoding special characters and unicode characters properly. + * @param value The string to write out. + * @throws IOException Thrown if an error occurs during write. + */ + public Serializer writeString(String value) throws IOException { + if (null == value) return writeNull(); + + writer.write('"'); + + char[] chars = value.toCharArray(); + + for (int i=0; i= 32) && (c <= 126)) { + writer.write(c); + } else { + writer.write("\\u"); + writer.write(rightAlignedZero(Integer.toHexString(c),4)); + } + } + } + + writer.write('"'); + + return this; + } + + /** + * Method to write out a generic JSON type. + * @param object The JSON compatible object to serialize. + * @throws IOException Thrown if an error occurs during write, or if a nonJSON compatible Java object is passed.. + */ + private Serializer write(Object object) throws IOException { + if (null == object) return writeNull(); + + // Serialize the various types! + Class clazz = object.getClass(); + if (NumberUtil.isNumber(clazz)) return writeNumber(object); + if (Boolean.class.isAssignableFrom(clazz)) return writeBoolean((Boolean) object); + if (JSONObject.class.isAssignableFrom(clazz)) return writeObject((JSONObject) object); + if (JSONArray.class.isAssignableFrom(clazz)) return writeArray((JSONArray) object); + if (JSONString.class.isAssignableFrom(clazz)) return writeRawString(((JSONString) object).toJSONString()); + if (String.class.isAssignableFrom(clazz)) return writeString((String) object); + + throw new IOException("Attempting to serialize unserializable object: '" + object + "'"); + } + + /** + * Method to write a complete JSON object to the stream. + * @param object The JSON object to write out. + * @throws IOException Thrown if an error occurs during write. + */ + public Serializer writeObject(JSONObject object) throws IOException { + if (null == object) return writeNull(); + + // write header + writeRawString("{"); + indentPush(); + + Enumeration iter = getPropertyNames(object); + + while ( iter.hasMoreElements() ) { + Object key = iter.nextElement(); + if (!(key instanceof String)) throw new IOException("attempting to serialize object with an invalid property name: '" + key + "'" ); + + Object value = object.get(key); + if (!JSONObject.isValidObject(value)) throw new IOException("attempting to serialize object with an invalid property value: '" + value + "'"); + + newLine(); + indent(); + writeString((String)key); + writeRawString(":"); + space(); + write(value); + + if (iter.hasMoreElements()) writeRawString(","); + } + + // write trailer + indentPop(); + newLine(); + indent(); + writeRawString("}"); + + return this; + } + + /** + * Method to write a JSON array out to the stream. + * @param value The JSON array to write out. + * @throws IOException Thrown if an error occurs during write. + */ + public Serializer writeArray(JSONArray value) throws IOException { + if (null == value) return writeNull(); + + // write header + writeRawString("["); + indentPush(); + + for (Enumeration iter=value.elements(); iter.hasMoreElements(); ) { + Object element = iter.nextElement(); + if (!JSONObject.isValidObject(element)) throw new IOException("attempting to serialize array with an invalid element: '" + value + "'"); + + newLine(); + indent(); + write(element); + + if (iter.hasMoreElements()) writeRawString(","); + } + + // write trailer + indentPop(); + newLine(); + indent(); + writeRawString("]"); + + return this; + } + + //--------------------------------------------------------------- + // pretty printing overridables + //--------------------------------------------------------------- + + /** + * Method to write a space to the output writer. + * @throws IOException Thrown if an error occurs during write. + */ + public void space() throws IOException { + } + + /** + * Method to write a newline to the output writer. + * @throws IOException Thrown if an error occurs during write. + */ + public void newLine() throws IOException { + } + + /** + * Method to write an indent to the output writer. + * @throws IOException Thrown if an error occurs during write. + */ + public void indent() throws IOException { + } + + /** + * Method to increase the indent depth of the output writer. + * @throws IOException Thrown if an error occurs during write. + */ + public void indentPush() { + } + + /** + * Method to reduce the indent depth of the output writer. + */ + public void indentPop() { + } + + /** + * Method to get a list of all the property names stored in a map. + */ + public Enumeration getPropertyNames(Hashtable map) { + return map.keys(); + } + + /** + * Method to write a String out to the writer, encoding special characters and unicode characters properly. + * @param value The string to write out. + */ + public static String quote(String value) { + if (value == null || value.length() == 0) { + return "\"\""; + } + + StringBuffer buf = new StringBuffer(); + char[] chars = value.toCharArray(); + + buf.append('"'); + for (int i=0; i= 32) && (c <= 126)) { + buf.append(c); + } else { + buf.append("\\u"); + buf.append(rightAlignedZero(Integer.toHexString(c),4)); + } + } + } + buf.append('"'); + + return buf.toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/json4j/internal/SerializerVerbose.java ---------------------------------------------------------------------- diff --git a/framework/ext/src/org/apache/cordova/json4j/internal/SerializerVerbose.java b/framework/ext/src/org/apache/cordova/json4j/internal/SerializerVerbose.java new file mode 100644 index 0000000..5132591 --- /dev/null +++ b/framework/ext/src/org/apache/cordova/json4j/internal/SerializerVerbose.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cordova.json4j.internal; + +import java.io.IOException; +import java.io.Writer; + +/** + * Internaql class for handling the serialization of JSON objects in a verbose + * format, meaning newlines and indention. + */ +public class SerializerVerbose extends Serializer { + + /** + * Internal tracker keeping indent position. + */ + private int indent = 0; + + /** + * The indent string to use when serializing. + */ + private String indentStr = "\t"; + + /** + * Constructor. + */ + public SerializerVerbose(Writer writer) { + super(writer); + } + + /** + * Constructor. + * @param Writer The writer to serialize JSON to. + * @param indentSpaces: How many spaces to indent by (0 to 8). + * The default indent is the TAB character. + */ + public SerializerVerbose(Writer writer, int indentSpaces) { + super(writer); + if(indentSpaces > 0 && indentSpaces < 8){ + this.indentStr = ""; + for(int i = 0; i < indentSpaces; i++){ + this.indentStr += " "; + } + } + } + + /** + * Method to write a space to the output writer. + * @throws IOException Thrown if an error occurs during write. + */ + public void space() throws IOException { + writeRawString(" "); + } + + /** + * Method to write a newline to the output writer. + * @throws IOException Thrown if an error occurs during write. + */ + public void newLine() throws IOException { + writeRawString("\n"); + } + + /** + * Method to write an indent to the output writer. + * @throws IOException Thrown if an error occurs during write. + */ + public void indent() throws IOException { + for (int i=0; i= Integer.MIN_VALUE)) { +// return new Integer(value.intValue()); +// } +// else { +// return value; +// } +// } + + if (string.equals("0")) { + return new Integer(0); +// } else if (string.startsWith("0") && string.length() > 1) { +// Long value = Long.valueOf(sign + string.substring(1),8); +// if (value.longValue() <= Integer.MAX_VALUE && (value.longValue() >= Integer.MIN_VALUE)) { +// return new Integer(value.intValue()); +// } +// else { +// return value; +// } + } + + /** + * We have to check for the exponential and treat appropriately + * Exponentials should be treated as Doubles. + */ + if (string.indexOf("e") != -1 || string.indexOf("E") != -1) { + return Double.valueOf(sign + string); + } else { + Long value = new Long(Long.parseLong(sign+ string, 10)); + //Long value = Long.valueOf(sign + string); + if (value.longValue() <= Integer.MAX_VALUE && (value.longValue() >= Integer.MIN_VALUE)) { + return new Integer(Integer.parseInt(sign + string, 10)); + } + else { + return value; + } + } + // else return new Integer(0); //MSN + } catch (NumberFormatException e) { + IOException iox = new IOException("Invalid number literal " + onLineCol(l,c)); + //MSNiox.setCause(e); + throw iox; + } + } + + /** + * Method to indicate if the character read is a HEX digit or not. + * @param c The character to check for being a HEX digit. + */ + private boolean isHexDigit(int c) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + return true; + } + + return false; + } + + /** + * Method to indicate if the character read is an OCTAL digit or not. + * @param c The character to check for being a OCTAL digit. + */ + private boolean isOctalDigit(int c) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + return true; + } + + return false; + } + + /** + * Method to indicate if the character read is a digit or not. + * @param c The character to check for being a digit. + */ + private boolean isDigitChar(int c) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + case 'e': + case 'E': + case 'x': + case 'X': + case '+': + case '-': + return true; + } + + return false; + } + + /** + * Method to read a partular character string. + * only really need to handle 'null', 'true', and 'false' + */ + private String readIdentifier() throws IOException { + StringBuffer sb = new StringBuffer(); + + if (this.strict) { + while ((-1 != lastChar) && ( (Character.isUpperCase((char)lastChar)) || (Character.isLowerCase((char)lastChar)) ) ){ + sb.append((char)lastChar); + readChar(); + } + } + else { + while ((-1 != lastChar) && isValidUnquotedChar((char)lastChar)) { + sb.append((char)lastChar); + readChar(); + } + } + + return sb.toString(); + } + + /** + * Method to read the next character from the string, keeping track of line/column position. + * + * @throws IOEXception Thrown when underlying reader throws an error. + */ + private void readChar() throws IOException { + if ('\n' == lastChar) { + this.colNo = 0; + this.lineNo++; + } + lastChar = reader.read(); + if (-1 == lastChar) return ; + colNo++; + } + + /** + * Method to generate a String indicationg the current line and column position in the JSON string. + */ + private String onLineCol(int line, int col) { + return "on line " + line + ", column " + col; + } + + /** + * Method to generate a String indicationg the current line and column position in the JSON string. + */ + public String onLineCol() { + return onLineCol(lineNo,colNo); + } + + /** + * High speed test for whitespace! Faster than the java one (from some testing). + * @return if the indicated character is whitespace. + */ + public boolean isWhitespace(char c) { + switch (c) { + case 9: //'unicode: 0009 + case 10: //'unicode: 000A' + case 11: //'unicode: 000B' + case 12: //'unicode: 000C' + case 13: //'unicode: 000D' + case 28: //'unicode: 001C' + case 29: //'unicode: 001D' + case 30: //'unicode: 001E' + case 31: //'unicode: 001F' + case ' ': // Space + //case Character.SPACE_SEPARATOR: + //case Character.LINE_SEPARATOR: + //MSN case Character.PARAGRAPH_SEPARATOR: + return true; + } + return false; + } + + /** + * For non strict mode, check if char is valid when not quoted. + * @param c + * @return if character is valid unquoted character. + */ + public boolean isValidUnquotedChar(char c) { + + if ( (Character.isDigit(c)) || (Character.isLowerCase(c)) || (Character.isUpperCase(c)) ) { + return true; + } + + switch (c) { + case '@': + case '-': + case '.': + case '$': + case '+': + case '!': + case '_': + return true; + } + return false; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/media/AudioCaptureListener.java ---------------------------------------------------------------------- diff --git a/framework/ext/src/org/apache/cordova/media/AudioCaptureListener.java b/framework/ext/src/org/apache/cordova/media/AudioCaptureListener.java new file mode 100644 index 0000000..a99d5b1 --- /dev/null +++ b/framework/ext/src/org/apache/cordova/media/AudioCaptureListener.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cordova.media; + +import net.rim.device.api.io.file.FileSystemJournal; +import net.rim.device.api.io.file.FileSystemJournalEntry; +import net.rim.device.api.io.file.FileSystemJournalListener; + +/** + * Listens for audio recording files that are added to file system. + *

+ * Audio recordings are added to the file system when the user stops the + * recording. The audio recording file extension is '.amr'. Therefore, we listen + * for the FileSystemJournalEntry.FILE_ADDED event, capturing when + * the new file is written. + *

+ * The file system notifications will arrive on the application event thread. + * When it receives a notification, it adds the image file path to a MediaQueue + * so that the capture thread can process the file. + */ +public class AudioCaptureListener implements FileSystemJournalListener { + /** + * Used to track file system changes. + */ + private long lastUSN = 0; + + /** + * Queue to send media files to for processing. + */ + private MediaQueue queue = null; + + /** + * Constructor. + */ + AudioCaptureListener(MediaQueue queue) { + this.queue = queue; + } + + public void fileJournalChanged() { + // next sequence number file system will use + long USN = FileSystemJournal.getNextUSN(); + + for (long i = USN - 1; i >= lastUSN && i < USN; --i) { + FileSystemJournalEntry entry = FileSystemJournal.getEntry(i); + if (entry == null) { + break; + } + + // has audio recording file has been added to the file system? + String path = entry.getPath(); + if (entry.getEvent() == FileSystemJournalEntry.FILE_ADDED + && path.endsWith(".amr")) { + // add file path to the capture queue + queue.add("file://" + path); + + break; + } + } + + // remember the file journal change number, + // so we don't search the same events again and again + lastUSN = USN; + } +} http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/media/AudioCaptureOperation.java ---------------------------------------------------------------------- diff --git a/framework/ext/src/org/apache/cordova/media/AudioCaptureOperation.java b/framework/ext/src/org/apache/cordova/media/AudioCaptureOperation.java new file mode 100644 index 0000000..cbd274d --- /dev/null +++ b/framework/ext/src/org/apache/cordova/media/AudioCaptureOperation.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cordova.media; + +import java.io.IOException; + +import javax.microedition.io.Connector; +import javax.microedition.io.file.FileConnection; + +import org.apache.cordova.file.File; +import org.apache.cordova.file.FileUtils; +import org.apache.cordova.util.Logger; + +import net.rim.device.api.io.MIMETypeAssociations; +import net.rim.device.api.ui.UiApplication; + +public class AudioCaptureOperation extends CaptureOperation { + + // content type + public static final String CONTENT_TYPE = "audio/"; + + // maximum duration to capture media (milliseconds) + private long duration = 0; + + // file system listener + private AudioCaptureListener listener = null; + + /** + * Creates and starts an audio capture operation. + * + * @param limit + * maximum number of media files to capture + * @param duration + * maximum duration to capture media (milliseconds) + * @param callbackId + * the callback to receive the files + * @param queue + * the queue from which to retrieve captured media files + */ + public AudioCaptureOperation(int limit, long duration, String callbackId, MediaQueue queue) { + super(limit, callbackId, queue); + + if (duration > 0) { + this.duration = duration; + } + + // listener to capture image files added to file system + this.listener = new AudioCaptureListener(queue); + + start(); + } + + /** + * Registers file system listener and launches native voice notes recorder + * application. + */ + protected void setup() { + // register listener for files being written + synchronized(UiApplication.getEventLock()) { + UiApplication.getUiApplication().addFileSystemJournalListener(listener); + } + + // launch the native voice notes recorder application + AudioControl.launchAudioRecorder(); + } + + /** + * Unregisters file system listener and closes native voice notes recorder + * application. + */ + protected void teardown() { + // remove file system listener + synchronized(UiApplication.getEventLock()) { + UiApplication.getUiApplication().removeFileSystemJournalListener(listener); + } + + // close the native voice notes recorder application + AudioControl.closeAudioRecorder(); + } + + /** + * Retrieves the file properties for the captured audio recording. + * + * @param filePath + * full path of the audio recording file + */ + protected void processFile(String filePath) { + Logger.log(this.getClass().getName() + ": processing file: " + filePath); + + File file = new File(FileUtils.stripSeparator(filePath)); + + // grab file properties + FileConnection fconn = null; + try { + fconn = (FileConnection) Connector.open(filePath, Connector.READ); + if (fconn.exists()) { + long size = fconn.fileSize(); + Logger.log(this.getClass().getName() + ": " + filePath + " size=" + + Long.toString(size) + " bytes"); + file.setLastModifiedDate(fconn.lastModified()); + file.setName(FileUtils.stripSeparator(fconn.getName())); + file.setSize(size); + file.setType(MIMETypeAssociations.getMIMEType(filePath)); + } + } + catch (IOException e) { + Logger.log(this.getClass().getName() + ": " + e); + } + finally { + try { + if (fconn != null) fconn.close(); + } catch (IOException ignored) {} + } + + addCaptureFile(file); + } +} http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/media/AudioControl.java ---------------------------------------------------------------------- diff --git a/framework/ext/src/org/apache/cordova/media/AudioControl.java b/framework/ext/src/org/apache/cordova/media/AudioControl.java new file mode 100644 index 0000000..e9d87c3 --- /dev/null +++ b/framework/ext/src/org/apache/cordova/media/AudioControl.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cordova.media; + +import org.apache.cordova.util.ApplicationUtils; +import org.apache.cordova.util.Logger; + +import net.rim.device.api.system.ApplicationDescriptor; +import net.rim.device.api.system.ApplicationManager; +import net.rim.device.api.system.ApplicationManagerException; +import net.rim.device.api.system.CodeModuleManager; + +public class AudioControl { + /** + * Determines if the native voice notes recorder application is installed + * on the device. + * + * @return true if native voice notes recorder application is installed + */ + public static boolean hasAudioRecorderApplication() { + return ApplicationUtils.isModuleInstalled("net_rim_bb_voicenotesrecorder"); + } + + /** + * Determines if the native voice notes recorder application is running in + * the foreground. + * + * @return true if native voice notes recorder application is running in + * foreground + */ + public static boolean isAudioRecorderActive() { + return ApplicationUtils.isApplicationInForeground("net_rim_bb_voicenotesrecorder"); + } + + /** + * Launches the native audio recorder application. + */ + public static void launchAudioRecorder() { + int handle = CodeModuleManager.getModuleHandle("net_rim_bb_voicenotesrecorder"); + ApplicationDescriptor ad = CodeModuleManager.getApplicationDescriptors(handle)[0]; + ApplicationDescriptor ad2 = new ApplicationDescriptor(ad, null); + try { + ApplicationManager.getApplicationManager().runApplication(ad2, true); + } + catch (ApplicationManagerException e) { + Logger.log(AudioControl.class.getName() + ": unable to launch net_rim_bb_voicenotesrecorder"); + } + } + + /** + * Closes the native audio recorder application. + */ + public static void closeAudioRecorder() { + if (!isAudioRecorderActive()) { + return; + } + ApplicationUtils.injectEscKeyPress(1); + } +} http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/media/CameraControl.java ---------------------------------------------------------------------- diff --git a/framework/ext/src/org/apache/cordova/media/CameraControl.java b/framework/ext/src/org/apache/cordova/media/CameraControl.java new file mode 100644 index 0000000..16c59cb --- /dev/null +++ b/framework/ext/src/org/apache/cordova/media/CameraControl.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cordova.media; + +import org.apache.cordova.util.ApplicationUtils; + +import net.rim.blackberry.api.invoke.CameraArguments; +import net.rim.blackberry.api.invoke.Invoke; +import net.rim.device.api.ui.UiApplication; + +public class CameraControl { + /** + * Determines if the native camera application is running in the foreground. + * + * @return true if native camera application is running in foreground + */ + public static boolean isCameraActive() { + return ApplicationUtils.isApplicationInForeground("net_rim_bb_camera"); + } + + /** + * Determines if the native video recorder application is running in the + * foreground. + * + * @return true if native video recorder application is running in + * foreground + */ + public static boolean isVideoRecorderActive() { + return ApplicationUtils.isApplicationInForeground("net_rim_bb_videorecorder"); + } + + /** + * Launches the native camera application. + */ + public static void launchCamera() { + synchronized(UiApplication.getEventLock()) { + Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA, + new CameraArguments()); + } + } + + /** + * Launches the native video recorder application. + */ + public static void launchVideoRecorder() { + synchronized(UiApplication.getEventLock()) { + Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA, + new CameraArguments(CameraArguments.ARG_VIDEO_RECORDER)); + } + } + + /** + * Closes the native camera application. + */ + public static void closeCamera() { + if (!isCameraActive()) { + return; + } + ApplicationUtils.injectEscKeyPress(2); + } + + /** + * Closes the native video recorder application. + */ + public static void closeVideoRecorder() { + if (!isVideoRecorderActive()) { + return; + } + ApplicationUtils.injectEscKeyPress(2); + } +} http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/media/CaptureControl.java ---------------------------------------------------------------------- diff --git a/framework/ext/src/org/apache/cordova/media/CaptureControl.java b/framework/ext/src/org/apache/cordova/media/CaptureControl.java new file mode 100644 index 0000000..b57b794 --- /dev/null +++ b/framework/ext/src/org/apache/cordova/media/CaptureControl.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cordova.media; + +import java.util.Enumeration; +import java.util.Vector; + +public class CaptureControl { + + /** + * Pending capture operations. + */ + private Vector pendingOperations = new Vector(); + + /** + * Singleton. + */ + private CaptureControl() {} + + /** + * Holds the singleton for lazy instantiation. + */ + private static class CaptureControlHolder { + static final CaptureControl INSTANCE = new CaptureControl(); + } + + /** + * Retrieves a CaptureControl instance. + * @return CaptureControl instance. + */ + public static final CaptureControl getCaptureControl() { + return CaptureControlHolder.INSTANCE; + } + + /** + * Add capture operation so we can stop it manually. + */ + public void addCaptureOperation(CaptureOperation operation) { + if (operation == null) { + return; + } + + synchronized (pendingOperations) { + pendingOperations.addElement(operation); + } + } + + /** + * Remove capture operation. + */ + public void removeCaptureOperation(CaptureOperation operation) { + if (operation == null) { + return; + } + + synchronized (pendingOperations) { + pendingOperations.removeElement(operation); + } + } + + /** + * Starts an image capture operation, during which a user can take multiple + * photos. The capture operation runs in the background. + * + * @param limit + * the maximum number of images to capture during the operation + * @param callbackId + * the callback to be invoked with capture file properties + */ + public void startImageCaptureOperation(int limit, String callbackId) { + // setup a queue to receive image file paths + MediaQueue queue = new MediaQueue(); + + // start a capture operation on a background thread + CaptureOperation operation = new ImageCaptureOperation(limit, + callbackId, queue); + + // track the operation so we can stop or cancel it later + addCaptureOperation(operation); + } + + /** + * Starts a video capture operation, during which a user can record multiple + * recordings. The capture operation runs in the background. + * + * @param limit + * the maximum number of images to capture during the operation + * @param callbackId + * the callback to be invoked with capture file properties + */ + public void startVideoCaptureOperation(int limit, String callbackId) { + // setup a queue to receive video recording file paths + MediaQueue queue = new MediaQueue(); + + // start a capture operation on a background thread + CaptureOperation operation = new VideoCaptureOperation(limit, + callbackId, queue); + + // track the operation so we can stop or cancel it later + addCaptureOperation(operation); + } + + /** + * Starts an audio capture operation using the native voice notes recorder + * application. + * + * @param limit + * the maximum number of audio clips to capture during the + * operation + * @param duration + * the maximum duration of each captured clip + * @param callbackId + * the callback to be invoked with the capture results + */ + public void startAudioCaptureOperation(int limit, long duration, String callbackId) { + // setup a queue to receive recording file paths + MediaQueue queue = new MediaQueue(); + + // start a capture operation on a background thread + CaptureOperation operation = new AudioCaptureOperation(limit, duration, + callbackId, queue); + + // track the operation so we can stop or cancel it later + addCaptureOperation(operation); + } + + /** + * Stops all pending capture operations. If the cancel + * parameter is true, no results will be sent via the callback + * mechanism and any captured files will be removed from the file system. + * + * @param cancel + * true if operations should be canceled + */ + public void stopPendingOperations(boolean cancel) { + // There are two scenarios where the capture operation would be stopped + // manually: + // 1- The user stops the capture application, and this application + // returns to the foreground. + // 2- It is canceled programmatically. No results should be sent. + synchronized (pendingOperations) { + for (Enumeration e = pendingOperations.elements(); e.hasMoreElements(); ) { + CaptureOperation operation = (CaptureOperation) e.nextElement(); + if (cancel) { + operation.cancel(); + } + else { + operation.stop(); + } + } + } + } +}