Compare commits
213 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fba87de064 | ||
|
|
576f8cba44 | ||
|
|
b9f9429542 | ||
|
|
bf0df9f3c3 | ||
|
|
1d458f2782 | ||
|
|
5ca4b4a884 | ||
|
|
5935052ead | ||
|
|
f3f2ad9144 | ||
|
|
9d1edc4554 | ||
|
|
5143b8a492 | ||
|
|
7c67f40fc4 | ||
|
|
167b600135 | ||
|
|
6c465e25d3 | ||
|
|
c183d06ed1 | ||
|
|
574731b853 | ||
|
|
94568a4ec8 | ||
|
|
b22c0e5b6d | ||
|
|
ab3347d25d | ||
|
|
66872de8e5 | ||
|
|
f6d4402fdc | ||
|
|
9f66ccb5f3 | ||
|
|
b339330592 | ||
|
|
56acd2953b | ||
|
|
6f8e13297e | ||
|
|
e9a9144098 | ||
|
|
d1905dbee8 | ||
|
|
adc88f01b7 | ||
|
|
ccf0c5db67 | ||
|
|
507554b8e8 | ||
|
|
4795133daf | ||
|
|
c1c9075962 | ||
|
|
a691e9f744 | ||
|
|
8969eed506 | ||
|
|
be83095edf | ||
|
|
5c7783305a | ||
|
|
f394f7457b | ||
|
|
d60806bfa6 | ||
|
|
32febcb892 | ||
|
|
6c594b6f5f | ||
|
|
67d46432ed | ||
|
|
adf4166caa | ||
|
|
40b9810a63 | ||
|
|
aa45670d87 | ||
|
|
e6d801a594 | ||
|
|
0aec2be4dd | ||
|
|
c86b618aaa | ||
|
|
451afabfbb | ||
|
|
f60049f713 | ||
|
|
ee0cd679d3 | ||
|
|
07ed6daeda | ||
|
|
b5800ced61 | ||
|
|
6d879f19f8 | ||
|
|
dde79c14f5 | ||
|
|
b08f245504 | ||
|
|
cbd0b7a94b | ||
|
|
f060d09272 | ||
|
|
6edad7e7de | ||
|
|
f0f596c892 | ||
|
|
dbe65f1d35 | ||
|
|
cdaf620f92 | ||
|
|
09b753d09e | ||
|
|
838fa5635f | ||
|
|
0a4d218010 | ||
|
|
24944cff22 | ||
|
|
34820f4344 | ||
|
|
56047e5fc8 | ||
|
|
80ee6c1a91 | ||
|
|
5649fbac20 | ||
|
|
586d3ecd60 | ||
|
|
9ebdca66d9 | ||
|
|
41ddcf2218 | ||
|
|
cbe1216bc2 | ||
|
|
234ee63859 | ||
|
|
2402541974 | ||
|
|
8b1fb30f59 | ||
|
|
bf6864bce0 | ||
|
|
34ebdaddc1 | ||
|
|
9f42772b7e | ||
|
|
47211f6cb3 | ||
|
|
95b48705fe | ||
|
|
6c1a2e1230 | ||
|
|
55b1e40885 | ||
|
|
d87f404d6e | ||
|
|
48c6ec87cf | ||
|
|
71972dcaab | ||
|
|
3fd158ad6e | ||
|
|
447af8da6a | ||
|
|
e8b80e8752 | ||
|
|
30a1164f6a | ||
|
|
80a5ea137b | ||
|
|
db8a8f3556 | ||
|
|
81195db87d | ||
|
|
23ec117f57 | ||
|
|
d3e24b0c48 | ||
|
|
58c3f9a187 | ||
|
|
03aaab6f8b | ||
|
|
c8af154205 | ||
|
|
6d1e0356ac | ||
|
|
825b9eafc2 | ||
|
|
0ad9ff0d87 | ||
|
|
8451133d00 | ||
|
|
be165c677f | ||
|
|
55ee289ed6 | ||
|
|
ca979a99e8 | ||
|
|
4ecbaa79cf | ||
|
|
c12f01261a | ||
|
|
d6d2749411 | ||
|
|
509588b130 | ||
|
|
e7411e8260 | ||
|
|
59f9b6f359 | ||
|
|
43df9f6b9c | ||
|
|
fd12f57f10 | ||
|
|
5edb3acad5 | ||
|
|
e35a8de4bb | ||
|
|
8b93e87e3e | ||
|
|
cb61e90148 | ||
|
|
c37b2d236b | ||
|
|
0c9295f8bc | ||
|
|
3b27d89c4a | ||
|
|
8356ac67e8 | ||
|
|
dffd2deb53 | ||
|
|
8ff48b371e | ||
|
|
6de66b87cb | ||
|
|
c8a521c182 | ||
|
|
5c48ccd92a | ||
|
|
f74d8aaf2b | ||
|
|
ffa1eb1ee9 | ||
|
|
24dfbfd84f | ||
|
|
ad6d71fef3 | ||
|
|
c178031f06 | ||
|
|
20db698475 | ||
|
|
dd624ccd9c | ||
|
|
ac504768b2 | ||
|
|
2d7b7160c3 | ||
|
|
2fbb9c285d | ||
|
|
47d99e5193 | ||
|
|
0437d6cc1a | ||
|
|
c6851cf7c5 | ||
|
|
45680a562e | ||
|
|
3b9d46fadc | ||
|
|
f840f3aceb | ||
|
|
afa1ecf3c5 | ||
|
|
295b9f4f5b | ||
|
|
79048a5a84 | ||
|
|
d683bd3744 | ||
|
|
9f5f4973ae | ||
|
|
441785b51d | ||
|
|
0d32115c3f | ||
|
|
e660768e4b | ||
|
|
01abb32025 | ||
|
|
d44d9ddca6 | ||
|
|
13f92b2b76 | ||
|
|
e6aa64760e | ||
|
|
3829df665f | ||
|
|
c8fafa6bbd | ||
|
|
aede2235d0 | ||
|
|
c56c73f250 | ||
|
|
dd0b6b1e30 | ||
|
|
5b324c85b0 | ||
|
|
fc9cff7d26 | ||
|
|
f3e70c79eb | ||
|
|
a705b72740 | ||
|
|
de6652dd9d | ||
|
|
c0dcbecbea | ||
|
|
b323f329cc | ||
|
|
2142d00bb9 | ||
|
|
4ce585be02 | ||
|
|
8ab1733374 | ||
|
|
e28f09e95b | ||
|
|
27e511b785 | ||
|
|
9dfa503bad | ||
|
|
5abe8dd506 | ||
|
|
e4119f3fd2 | ||
|
|
480e5ca4d1 | ||
|
|
f4cf2cecb5 | ||
|
|
5ab5cf03b5 | ||
|
|
13ba1e4900 | ||
|
|
17c919edd9 | ||
|
|
99b3693f40 | ||
|
|
483bb53d9c | ||
|
|
80ec23887e | ||
|
|
ea81b97bfc | ||
|
|
be39bf8d91 | ||
|
|
ca66c4bf59 | ||
|
|
4192489836 | ||
|
|
2e4667da88 | ||
|
|
9718aa5d4a | ||
|
|
d5dd43289b | ||
|
|
1bd7a662df | ||
|
|
327589a1d7 | ||
|
|
531b8f641f | ||
|
|
8ac274cdca | ||
|
|
fea79bc971 | ||
|
|
f2526bbc78 | ||
|
|
1794f2e047 | ||
|
|
b99e9abb5f | ||
|
|
e77f9bb8fc | ||
|
|
628f88cf79 | ||
|
|
87238f26f6 | ||
|
|
95013e87dd | ||
|
|
d604e8b9b4 | ||
|
|
9a2eb04054 | ||
|
|
f34da8a96f | ||
|
|
527f17d19e | ||
|
|
2818e05e71 | ||
|
|
49b50ce66c | ||
|
|
b793fbfc28 | ||
|
|
59ff94fefb | ||
|
|
f3c29840a7 | ||
|
|
6dabe4c010 | ||
|
|
8ecfcb12c7 | ||
|
|
ae8bc77ee7 | ||
|
|
e25490751c |
4
NOTICE
@@ -1,5 +1,5 @@
|
||||
Apache Callback
|
||||
Copyright 2011 The Apache Software Foundation
|
||||
Apache Cordova
|
||||
Copyright 2012 The Apache Software Foundation
|
||||
|
||||
This product includes software developed by
|
||||
The Apache Software Foundation (http://www.apache.org)
|
||||
|
||||
@@ -20,6 +20,10 @@ Requires
|
||||
- Android SDK [http://developer.android.com](http://developer.android.com)
|
||||
- Apache Commons Codec [http://commons.apache.org/codec/](http://commons.apache.org/codec/)
|
||||
|
||||
Test Requirements
|
||||
---
|
||||
- JUnit - [https://github.com/KentBeck/junit](https://github.com/KentBeck/junit)
|
||||
|
||||
Building
|
||||
---
|
||||
|
||||
@@ -98,6 +102,9 @@ Importing a Cordova Android Project into Eclipse
|
||||
5. Right click on the project root: Run as > Run Configurations
|
||||
6. Click on the Target tab and select Manual (this way you can choose the emulator or device to build to)
|
||||
|
||||
Running Tests
|
||||
----
|
||||
Please see details under test/README.md.
|
||||
|
||||
Further Reading
|
||||
---
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#! /usr/bin/env node
|
||||
require('nodeunit').reporters.default.run(['bin/tests'])
|
||||
47
bin/bench
@@ -1,47 +0,0 @@
|
||||
#! /bin/sh
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
#
|
||||
# Creates an app in `./bench` that posts results to http://cordova-bench.heroku.com with current cordova/Android sha.
|
||||
#
|
||||
# USAGE
|
||||
# ./bin/bench
|
||||
#
|
||||
|
||||
# clobber any existing bench
|
||||
if [ -e ./bench ]
|
||||
then
|
||||
rm -rf ./bench
|
||||
fi
|
||||
|
||||
# create a benching app
|
||||
./bin/create ./bench org.apache.cordova.bench cordovaBench
|
||||
|
||||
# grab the latest bench www code
|
||||
git clone git@github.com:brianleroux/cordova-bench.git
|
||||
|
||||
# copy it into the app
|
||||
cat ./cordova-bench/www/index.html > ./bench/assets/www/index.html
|
||||
#cat ~/Desktop/cordova-bench/www/index.html > ./bench/assets/www/index.html
|
||||
|
||||
# clean up
|
||||
rm -rf ./cordova-bench
|
||||
|
||||
# launch to the first device found
|
||||
./bin/debug ./bench
|
||||
111
bin/create
@@ -23,52 +23,103 @@
|
||||
#
|
||||
set -e
|
||||
|
||||
if [ -n "$1" ] && [ "$1" == "-h" ]
|
||||
then
|
||||
echo 'usage: create path package activity'
|
||||
echo "Make sure the Android SDK tools folder is in your PATH!"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
BUILD_PATH=$( cd "$( dirname "$0" )/.." && pwd )
|
||||
VERSION=$(cat $BUILD_PATH/VERSION)
|
||||
|
||||
PROJECT_PATH=${1:-"./example"}
|
||||
PACKAGE=${2:-"org.apache.cordova.example"}
|
||||
ACTIVITY=${3:-"cordovaExample"}
|
||||
TARGET=$(android list targets | grep 'id: ' | sed 's/id: \([0-9]*\).*/\1/g' | tail -1)
|
||||
VERSION=$(cat ./VERSION)
|
||||
|
||||
# clobber any existing example
|
||||
if [ $# -eq 0 ]
|
||||
if [ -d $PROJECT_PATH ]
|
||||
then
|
||||
rm -rf $PROJECT_PATH
|
||||
echo "Project already exists! Delete and recreate"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# update the cordova-android framework for the desired target
|
||||
android update project --target $TARGET --path ./framework
|
||||
# cleanup after exit and/or on error
|
||||
function on_exit {
|
||||
echo "Cleaning up ..."
|
||||
# [ -f $BUILD_PATH/framework/libs/commons-codec-1.6.jar ] && rm $BUILD_PATH/framework/libs/commons-codec-1.6.jar
|
||||
# [ -d $BUILD_PATH/framework/libs ] && rmdir $BUILD_PATH/framework/libs
|
||||
[ -f $BUILD_PATH/framework/assets/www/cordova-$VERSION.js ] && rm $BUILD_PATH/framework/assets/www/cordova-$VERSION.js
|
||||
[ -f $BUILD_PATH/framework/cordova-$VERSION.jar ] && rm $BUILD_PATH/framework/cordova-$VERSION.jar
|
||||
}
|
||||
|
||||
if [ ! -e ./framework/libs/commons-codec-1.6.jar ]; then
|
||||
function on_error {
|
||||
echo "An error occured. Deleting project..."
|
||||
[ -d $PROJECT_PATH ] && rm -rf $PROJECT_PATH
|
||||
}
|
||||
|
||||
# we do not want the script to silently fail
|
||||
trap on_error ERR
|
||||
trap on_exit EXIT
|
||||
|
||||
ANDROID_BIN=$( which android )
|
||||
PACKAGE_AS_PATH=$(echo $PACKAGE | sed 's/\./\//g')
|
||||
ACTIVITY_PATH=$PROJECT_PATH/src/$PACKAGE_AS_PATH/$ACTIVITY.java
|
||||
MANIFEST_PATH=$PROJECT_PATH/AndroidManifest.xml
|
||||
|
||||
TARGET=$($ANDROID_BIN list targets | grep id: | tail -1 | cut -f 2 -d ' ' )
|
||||
|
||||
# update the cordova-android framework for the desired target
|
||||
$ANDROID_BIN update project --target $TARGET --path $BUILD_PATH/framework &> /dev/null
|
||||
|
||||
if [ ! -e $BUILD_PATH/framework/libs/commons-codec-1.6.jar ]; then
|
||||
# Use curl to get the jar (TODO: Support Apache Mirrors)
|
||||
curl -OL http://mirror.symnds.com/software/Apache//commons/codec/binaries/commons-codec-1.6-bin.zip
|
||||
unzip commons-codec-1.6-bin.zip
|
||||
mkdir -p ./framework/libs
|
||||
cp commons-codec-1.6/commons-codec-1.6.jar ./framework/libs/
|
||||
echo "Downloading common-codecs-1.6 ..."
|
||||
curl -OL http://mirror.symnds.com/software/Apache//commons/codec/binaries/commons-codec-1.6-bin.zip &> /dev/null
|
||||
unzip commons-codec-1.6-bin.zip &> /dev/null
|
||||
mkdir -p $BUILD_PATH/framework/libs
|
||||
cp commons-codec-1.6/commons-codec-1.6.jar $BUILD_PATH/framework/libs
|
||||
# cleanup yo
|
||||
rm commons-codec-1.6-bin.zip && rm -rf commons-codec-1.6
|
||||
fi
|
||||
|
||||
# compile cordova.js and cordova.jar
|
||||
cd ./framework && ant jar && cd ../
|
||||
echo "Building cordova-$VERSION.jar and cordova-$VERSION.js ..."
|
||||
(cd $BUILD_PATH/framework && ant jar &> /dev/null )
|
||||
|
||||
# copy all the bin scripts etc in there
|
||||
cp -R ./bin/templates/project/ $PROJECT_PATH
|
||||
# create new android project
|
||||
echo "Creating a new cordova android project ..."
|
||||
$ANDROID_BIN create project --target $TARGET --path $PROJECT_PATH --package $PACKAGE --activity $ACTIVITY &> /dev/null
|
||||
|
||||
# copy in cordova.js
|
||||
cp ./framework/assets/www/cordova-$VERSION.js $PROJECT_PATH/.cordova/android/cordova-$VERSION.js
|
||||
# copy project template
|
||||
echo "Copying assets and resources ..."
|
||||
cp -r $BUILD_PATH/bin/templates/project/assets $PROJECT_PATH
|
||||
cp -r $BUILD_PATH/bin/templates/project/res $PROJECT_PATH
|
||||
|
||||
# copy in cordova.jar
|
||||
cp ./framework/cordova-$VERSION.jar $PROJECT_PATH/.cordova/android/cordova-$VERSION.jar
|
||||
# copy cordova.js, cordova.jar and res/xml
|
||||
echo "Setting up config and plugins list ..."
|
||||
cp -r $BUILD_PATH/framework/res/xml $PROJECT_PATH/res
|
||||
|
||||
# copy in res/xml
|
||||
cp ./framework/res/xml/cordova.xml $PROJECT_PATH/.cordova/android/cordova.xml
|
||||
cp ./framework/res/xml/plugins.xml $PROJECT_PATH/.cordova/android/plugins.xml
|
||||
echo "Adding cordova-$VERSION.js and cordova-$VERSION.jar ..."
|
||||
cp $BUILD_PATH/framework/assets/www/cordova-$VERSION.js $PROJECT_PATH/assets/www/cordova-$VERSION.js
|
||||
cp $BUILD_PATH/framework/cordova-$VERSION.jar $PROJECT_PATH/libs/cordova-$VERSION.jar
|
||||
|
||||
# app properties
|
||||
cat > $PROJECT_PATH/.cordova/config <<eom
|
||||
VERSION=$VERSION
|
||||
PROJECT_PATH=$PROJECT_PATH
|
||||
PACKAGE=$PACKAGE
|
||||
ACTIVITY=$ACTIVITY
|
||||
TARGET=$TARGET
|
||||
eom
|
||||
# interpolate the activity name and package
|
||||
echo "Updating Activity and AndroidManifest ..."
|
||||
cp $BUILD_PATH/bin/templates/project/Activity.java $ACTIVITY_PATH
|
||||
sed -i '' -e "s/__ACTIVITY__/${ACTIVITY}/g" $ACTIVITY_PATH
|
||||
sed -i '' -e "s/__ID__/${PACKAGE}/g" $ACTIVITY_PATH
|
||||
|
||||
(cd $PROJECT_PATH && ./cordova/create)
|
||||
cp $BUILD_PATH/bin/templates/project/AndroidManifest.xml $MANIFEST_PATH
|
||||
sed -i '' -e "s/__ACTIVITY__/${ACTIVITY}/g" $MANIFEST_PATH
|
||||
sed -i '' -e "s/__PACKAGE__/${PACKAGE}/g" $MANIFEST_PATH
|
||||
|
||||
# creating cordova folder and copying emulate/debug/log/launch scripts
|
||||
mkdir $PROJECT_PATH/cordova
|
||||
cp $BUILD_PATH/bin/templates/cordova/appinfo.jar $PROJECT_PATH/cordova/appinfo.jar
|
||||
cp $BUILD_PATH/bin/templates/cordova/cordova $PROJECT_PATH/cordova/cordova
|
||||
cp $BUILD_PATH/bin/templates/cordova/debug $PROJECT_PATH/cordova/debug
|
||||
cp $BUILD_PATH/bin/templates/cordova/clean $PROJECT_PATH/cordova/clean
|
||||
cp $BUILD_PATH/bin/templates/cordova/log $PROJECT_PATH/cordova/log
|
||||
cp $BUILD_PATH/bin/templates/cordova/emulate $PROJECT_PATH/cordova/emulate
|
||||
cp $BUILD_PATH/bin/templates/cordova/BOOM $PROJECT_PATH/cordova/BOOM
|
||||
|
||||
@@ -1 +1,15 @@
|
||||
cscript bin\create.js %*
|
||||
@ECHO OFF
|
||||
IF NOT DEFINED JAVA_HOME GOTO MISSING
|
||||
FOR %%X in (java.exe ant.bat android.bat) do (
|
||||
SET FOUND=%%~$PATH:X
|
||||
IF NOT DEFINED FOUND GOTO MISSING
|
||||
)
|
||||
cscript %~dp0\create.js %*
|
||||
GOTO END
|
||||
:MISSING
|
||||
ECHO Missing one of the following:
|
||||
ECHO JDK: http://java.oracle.com
|
||||
ECHO Android SDK: http://developer.android.com
|
||||
ECHO Apache ant: http://ant.apache.org
|
||||
EXIT /B 1
|
||||
:END
|
||||
|
||||
191
bin/create.js
@@ -24,14 +24,19 @@
|
||||
* ./create [path package activity]
|
||||
*/
|
||||
|
||||
var fso = WScript.CreateObject('Scripting.FileSystemObject');
|
||||
|
||||
function read(filename) {
|
||||
WScript.Echo('Reading in ' + filename);
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(filename, 1);
|
||||
var s=f.ReadAll();
|
||||
f.Close();
|
||||
return s;
|
||||
}
|
||||
function setTarget() {
|
||||
var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/id:\s\d+/g);
|
||||
return targets[targets.length - 1].replace(/id: /, ""); // TODO: give users the option to set their target
|
||||
}
|
||||
function write(filename, contents) {
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(filename, 2, true);
|
||||
@@ -41,24 +46,65 @@ function write(filename, contents) {
|
||||
function replaceInFile(filename, regexp, replacement) {
|
||||
write(filename, read(filename).replace(regexp, replacement));
|
||||
}
|
||||
function exec(s, output) {
|
||||
WScript.Echo('Executing ' + s);
|
||||
var o=shell.Exec(s);
|
||||
while (o.Status == 0) {
|
||||
WScript.Sleep(100);
|
||||
function exec(command) {
|
||||
var oShell=shell.Exec(command);
|
||||
while (oShell.Status == 0) {
|
||||
WScript.sleep(100);
|
||||
}
|
||||
WScript.Echo("Command exited with code " + o.Status);
|
||||
}
|
||||
|
||||
function fork(s) {
|
||||
WScript.Echo('Executing ' + s);
|
||||
var o=shell.Exec(s);
|
||||
while (o.Status != 1) {
|
||||
WScript.Sleep(100);
|
||||
function cleanup() {
|
||||
// Cleanup
|
||||
// if(fso.FileExists(ROOT + '\\framework\\libs\\commons-codec-1.6.jar')) {
|
||||
// fso.DeleteFile(ROOT + '\\framework\\libs\\commons-codec-1.6.jar');
|
||||
// fso.DeleteFolder(ROOT + '\\framework\\libs', true);
|
||||
// }
|
||||
if(fso.FileExists(ROOT + '\\framework\\cordova-'+VERSION+'.jar')) {
|
||||
fso.DeleteFile(ROOT + '\\framework\\cordova-'+VERSION+'.jar');
|
||||
}
|
||||
if(fso.FileExists(ROOT + '\\framework\\assets\\www\\cordova-'+VERSION+'.js')) {
|
||||
fso.DeleteFile(ROOT + '\\framework\\assets\\www\\cordova-'+VERSION+'.js');
|
||||
}
|
||||
}
|
||||
|
||||
function downloadCommonsCodec() {
|
||||
if (!fso.FileExists(ROOT + '\\framework\\libs\\commons-codec-1.6.jar')) {
|
||||
// We need the .jar
|
||||
var url = 'http://mirror.symnds.com/software/Apache//commons/codec/binaries/commons-codec-1.6-bin.zip';
|
||||
var libsPath = ROOT + '\\framework\\libs';
|
||||
var savePath = libsPath + '\\commons-codec-1.6-bin.zip';
|
||||
if (!fso.FileExists(savePath)) {
|
||||
if(!fso.FolderExists(ROOT + '\\framework\\libs')) {
|
||||
fso.CreateFolder(libsPath);
|
||||
}
|
||||
// We need the zip to get the jar
|
||||
var xhr = WScript.CreateObject('MSXML2.XMLHTTP');
|
||||
xhr.open('GET', url, false);
|
||||
xhr.send();
|
||||
if (xhr.status == 200) {
|
||||
var stream = WScript.CreateObject('ADODB.Stream');
|
||||
stream.Open();
|
||||
stream.Type = 1;
|
||||
stream.Write(xhr.ResponseBody);
|
||||
stream.Position = 0;
|
||||
stream.SaveToFile(savePath);
|
||||
stream.Close();
|
||||
} else {
|
||||
WScript.Echo('Could not retrieve the commons-codec. Please download it yourself and put into the framework/libs directory. This process may fail now. Sorry.');
|
||||
}
|
||||
}
|
||||
var app = WScript.CreateObject('Shell.Application');
|
||||
var source = app.NameSpace(savePath).Items();
|
||||
var target = app.NameSpace(ROOT + '\\framework\\libs');
|
||||
target.CopyHere(source, 256);
|
||||
|
||||
// Move the jar into libs
|
||||
fso.MoveFile(ROOT + '\\framework\\libs\\commons-codec-1.6\\commons-codec-1.6.jar', ROOT + '\\framework\\libs\\commons-codec-1.6.jar');
|
||||
|
||||
// Clean up
|
||||
fso.DeleteFile(ROOT + '\\framework\\libs\\commons-codec-1.6-bin.zip');
|
||||
fso.DeleteFolder(ROOT + '\\framework\\libs\\commons-codec-1.6', true);
|
||||
}
|
||||
WScript.Echo(o.StdOut.ReadAll());
|
||||
WScript.Echo(o.StdErr.ReadAll());
|
||||
WScript.Echo("Command exited with code " + o.Status);
|
||||
}
|
||||
|
||||
var args = WScript.Arguments, PROJECT_PATH="example",
|
||||
@@ -69,106 +115,65 @@ var args = WScript.Arguments, PROJECT_PATH="example",
|
||||
var ROOT = WScript.ScriptFullName.split('\\bin\\create.js').join('');
|
||||
|
||||
if (args.Count() == 3) {
|
||||
WScript.Echo('Found expected arguments');
|
||||
PROJECT_PATH=args(0);
|
||||
PACKAGE=args(1);
|
||||
ACTIVITY=args(2);
|
||||
}
|
||||
|
||||
if(fso.FolderExists(PROJECT_PATH)) {
|
||||
WScript.Echo("Project already exists!");
|
||||
WScript.Quit(1);
|
||||
}
|
||||
|
||||
var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
|
||||
var ACTIVITY_PATH=PROJECT_PATH+'\\src\\'+PACKAGE_AS_PATH+'\\'+ACTIVITY+'.java';
|
||||
var MANIFEST_PATH=PROJECT_PATH+'\\AndroidManifest.xml';
|
||||
var TARGET=shell.Exec('android.bat list targets').StdOut.ReadAll().match(/id:\s([0-9]).*/)[1];
|
||||
var VERSION=read('VERSION').replace(/\r\n/,'').replace(/\n/,'');
|
||||
|
||||
WScript.Echo("Project path: " + PROJECT_PATH);
|
||||
WScript.Echo("Package: " + PACKAGE);
|
||||
WScript.Echo("Activity: " + ACTIVITY);
|
||||
WScript.Echo("Package as path: " + PACKAGE_AS_PATH);
|
||||
WScript.Echo("Activity path: " + ACTIVITY_PATH);
|
||||
WScript.Echo("Manifest path: " + MANIFEST_PATH);
|
||||
WScript.Echo("Cordova version: " + VERSION);
|
||||
|
||||
// TODO: clobber any existing example
|
||||
|
||||
/*
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
rm -rf $PROJECT_PATH
|
||||
fi
|
||||
*/
|
||||
|
||||
var TARGET=setTarget();
|
||||
var VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
|
||||
// create the project
|
||||
exec('android.bat create project --target '+TARGET+' --path '+PROJECT_PATH+' --package '+PACKAGE+' --activity '+ACTIVITY);
|
||||
|
||||
// update the cordova framework project to a target that exists on this machine
|
||||
exec('android.bat update project --target '+TARGET+' --path framework');
|
||||
exec('android.bat update project --target '+TARGET+' --path '+ROOT+'\\framework');
|
||||
|
||||
// pull down commons codec if necessary
|
||||
var fso = WScript.CreateObject('Scripting.FileSystemObject');
|
||||
if (!fso.FileExists(ROOT + '\\framework\\libs\\commons-codec-1.6.jar')) {
|
||||
// We need the .jar
|
||||
var url = 'http://mirror.symnds.com/software/Apache//commons/codec/binaries/commons-codec-1.6-bin.zip';
|
||||
var savePath = ROOT + '\\framework\\libs\\commons-codec-1.6-bin.zip';
|
||||
if (!fso.FileExists(savePath)) {
|
||||
// We need the zip to get the jar
|
||||
var xhr = WScript.CreateObject('MSXML2.XMLHTTP');
|
||||
xhr.open('GET', url, false);
|
||||
xhr.send();
|
||||
if (xhr.status == 200) {
|
||||
var stream = WScript.CreateObject('ADODB.Stream');
|
||||
stream.Open();
|
||||
stream.Type = 1;
|
||||
stream.Write(xhr.ResponseBody);
|
||||
stream.Position = 0;
|
||||
stream.SaveToFile(savePath);
|
||||
stream.Close();
|
||||
} else {
|
||||
WScript.Echo('Could not retrieve the commons-codec. Please download it yourself and put into the framework/libs directory. This process may fail now. Sorry.');
|
||||
}
|
||||
}
|
||||
var app = WScript.CreateObject('Shell.Application');
|
||||
var source = app.NameSpace(savePath).Items();
|
||||
var target = app.NameSpace(ROOT + '\\framework\\libs');
|
||||
target.CopyHere(source, 256);
|
||||
|
||||
// Move the jar into libs
|
||||
fso.MoveFile(ROOT + '\\framework\\libs\\commons-codec-1.6\\commons-codec-1.6.jar', ROOT + '\\framework\\libs\\commons-codec-1.6.jar');
|
||||
|
||||
// Clean up
|
||||
fso.DeleteFile(ROOT + '\\framework\\libs\\commons-codec-1.6-bin.zip');
|
||||
fso.DeleteFolder(ROOT + '\\framework\\libs\\commons-codec-1.6', true);
|
||||
}
|
||||
downloadCommonsCodec();
|
||||
|
||||
|
||||
// compile cordova.js and cordova.jar
|
||||
// if you see an error about "Unable to resolve target" then you may need to
|
||||
// update your android tools or install an additional Android platform version
|
||||
exec('ant.bat -f framework\\build.xml jar');
|
||||
exec('ant.bat -f '+ ROOT +'\\framework\\build.xml jar');
|
||||
|
||||
// copy in the project template
|
||||
exec('cmd /c xcopy bin\\templates\\project\\* '+PROJECT_PATH+' /S /Y');
|
||||
|
||||
// copy example www assets
|
||||
exec('cmd /c xcopy ' + PROJECT_PATH + '\\cordova\\assets ' + PROJECT_PATH + ' /S /Y');
|
||||
exec('%comspec% /c xcopy '+ ROOT + '\\bin\\templates\\project\\res '+PROJECT_PATH+'\\res\\ /E /Y');
|
||||
exec('%comspec% /c xcopy '+ ROOT + '\\bin\\templates\\project\\assets '+PROJECT_PATH+'\\assets\\ /E /Y');
|
||||
exec('%comspec% /c copy '+ROOT+'\\bin\\templates\\project\\AndroidManifest.xml ' + PROJECT_PATH + '\\AndroidManifest.xml /Y');
|
||||
exec('%comspec% /c copy '+ROOT+'\\bin\\templates\\project\\Activity.java '+ ACTIVITY_PATH +' /Y');
|
||||
|
||||
// copy in cordova.js
|
||||
exec('cmd /c copy framework\\assets\\js\\cordova.android.js '+PROJECT_PATH+'\\.cordova\\android\\cordova-'+VERSION+'.js /Y');
|
||||
exec('%comspec% /c copy '+ROOT+'\\framework\\assets\\www\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
|
||||
|
||||
// copy in cordova.jar
|
||||
exec('cmd /c copy framework\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\.cordova\\android\\cordova-'+VERSION+'.jar /Y');
|
||||
exec('%comspec% /c copy '+ROOT+'\\framework\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
|
||||
|
||||
// copy in xml
|
||||
exec('cmd /c copy framework\\res\\xml\\cordova.xml ' + PROJECT_PATH + '\\.cordova\\android\\cordova.xml /Y');
|
||||
exec('cmd /c copy framework\\res\\xml\\plugins.xml ' + PROJECT_PATH + '\\.cordova\\android\\plugins.xml /Y');
|
||||
fso.CreateFolder(PROJECT_PATH + '\\res\\xml');
|
||||
exec('%comspec% /c copy '+ROOT+'\\framework\\res\\xml\\cordova.xml ' + PROJECT_PATH + '\\res\\xml\\cordova.xml /Y');
|
||||
exec('%comspec% /c copy '+ROOT+'\\framework\\res\\xml\\plugins.xml ' + PROJECT_PATH + '\\res\\xml\\plugins.xml /Y');
|
||||
|
||||
// write out config file
|
||||
write(PROJECT_PATH + '\\.cordova\\config',
|
||||
'VERSION=' + VERSION + '\r\n' +
|
||||
'PROJECT_PATH=' + PROJECT_PATH + '\r\n' +
|
||||
'PACKAGE=' + PACKAGE + '\r\n' +
|
||||
'ACTIVITY=' + ACTIVITY + '\r\n' +
|
||||
'TARGET=' + TARGET);
|
||||
// copy cordova scripts
|
||||
fso.CreateFolder(PROJECT_PATH + '\\cordova');
|
||||
exec('%comspec% /c copy '+ROOT+'\\bin\\templates\\cordova\\appinfo.jar ' + PROJECT_PATH + '\\cordova\\appinfo.jar /Y');
|
||||
exec('%comspec% /c copy '+ROOT+'\\bin\\templates\\cordova\\cordova.js ' + PROJECT_PATH + '\\cordova\\cordova.js /Y');
|
||||
exec('%comspec% /c copy '+ROOT+'\\bin\\templates\\cordova\\cordova.bat ' + PROJECT_PATH + '\\cordova\\cordova.bat /Y');
|
||||
exec('%comspec% /c copy '+ROOT+'\\bin\\templates\\cordova\\clean.bat ' + PROJECT_PATH + '\\cordova\\clean.bat /Y');
|
||||
exec('%comspec% /c copy '+ROOT+'\\bin\\templates\\cordova\\debug.bat ' + PROJECT_PATH + '\\cordova\\debug.bat /Y');
|
||||
exec('%comspec% /c copy '+ROOT+'\\bin\\templates\\cordova\\log.bat ' + PROJECT_PATH + '\\cordova\\log.bat /Y');
|
||||
exec('%comspec% /c copy '+ROOT+'\\bin\\templates\\cordova\\emulate.bat ' + PROJECT_PATH + '\\cordova\\emulate.bat /Y');
|
||||
exec('%comspec% /c copy '+ROOT+'\\bin\\templates\\cordova\\BOOM.bat ' + PROJECT_PATH + '\\cordova\\BOOM.bat /Y');
|
||||
|
||||
// run project-specific create process
|
||||
fork('cscript.exe ' + PROJECT_PATH + '\\cordova\\create.js');
|
||||
// interpolate the activity name and package
|
||||
replaceInFile(ACTIVITY_PATH, /__ACTIVITY__/, ACTIVITY);
|
||||
replaceInFile(ACTIVITY_PATH, /__ID__/, PACKAGE);
|
||||
|
||||
replaceInFile(MANIFEST_PATH, /__ACTIVITY__/, ACTIVITY);
|
||||
replaceInFile(MANIFEST_PATH, /__PACKAGE__/, PACKAGE);
|
||||
|
||||
cleanup();
|
||||
|
||||
@@ -18,9 +18,5 @@
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://git-wip-us.apache.org/repos/asf/incubator-cordova-android.git"
|
||||
},
|
||||
"dependencies":{
|
||||
"coffee-script":"1.1.2",
|
||||
"nodeunit":"0.5.3"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
bin/templates/cordova/ApplicationInfo/ApplicationInfo.class
Normal file
44
bin/templates/cordova/ApplicationInfo/ApplicationInfo.java
Normal file
@@ -0,0 +1,44 @@
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.xml.sax.SAXException;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ApplicationInfo {
|
||||
private static void parseAndroidManifest(String path) {
|
||||
// System.out.println(path);
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
Document dom;
|
||||
try {
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
dom = db.parse(path);
|
||||
|
||||
// getting package information
|
||||
Element manifest = dom.getDocumentElement();
|
||||
String pakkage = manifest.getAttribute("package");
|
||||
|
||||
// getting activity name
|
||||
String activity = ((Element)dom.getElementsByTagName("activity").item(0)).getAttribute("android:name");
|
||||
System.out.println(String.format("%s/.%s", pakkage, activity.replace(".", "")));
|
||||
} catch(ParserConfigurationException pce) {
|
||||
pce.printStackTrace();
|
||||
} catch(SAXException se) {
|
||||
se.printStackTrace();
|
||||
} catch(IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String path;
|
||||
if(args.length > 0) {
|
||||
path = args[0];
|
||||
} else {
|
||||
path = System.getProperty("user.dir") + "/../AndroidManifest.xml";
|
||||
}
|
||||
parseAndroidManifest(path);
|
||||
}
|
||||
}
|
||||
7
bin/templates/cordova/BOOM
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
|
||||
|
||||
bash $CORDOVA_PATH/cordova BOOM
|
||||
1
bin/templates/cordova/BOOM.bat
Normal file
@@ -0,0 +1 @@
|
||||
%~dp0\cordova.bat BOOM
|
||||
BIN
bin/templates/cordova/appinfo.jar
Normal file
7
bin/templates/cordova/clean
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
|
||||
|
||||
bash $CORDOVA_PATH/cordova clean
|
||||
1
bin/templates/cordova/clean.bat
Normal file
@@ -0,0 +1 @@
|
||||
%~dp0\cordova.bat clean
|
||||
91
bin/templates/cordova/cordova
Normal file
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
PROJECT_PATH=$( cd "$( dirname "$0" )/.." && pwd )
|
||||
|
||||
function check_devices {
|
||||
local devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}'`
|
||||
if [ -z "$devices" ] ; then
|
||||
echo "1"
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
}
|
||||
|
||||
function emulate {
|
||||
declare -a avd_list=($(android list avd | grep "Name:" | cut -f 2 -d ":" | xargs))
|
||||
# we need to start adb-server
|
||||
adb start-server 1>/dev/null
|
||||
|
||||
# Do not launch an emulator if there is already one running or if a device is attached
|
||||
if [ $(check_devices) == 0 ] ; then
|
||||
echo "Device attached or emulator already running"
|
||||
return
|
||||
fi
|
||||
|
||||
local avd_id="1000" #FIXME: hopefully user does not have 1000 AVDs
|
||||
# User has no AVDs
|
||||
if [ ${#avd_list[@]} == 0 ]
|
||||
then
|
||||
echo "You don't have any Android Virtual Devices. Please create at least one AVD."
|
||||
echo "android"
|
||||
fi
|
||||
# User has only one AVD
|
||||
if [ ${#avd_list[@]} == 1 ]
|
||||
then
|
||||
emulator -cpu-delay 0 -no-boot-anim -cache /tmp/cache -avd ${avd_list[0]} 1> /dev/null 2>&1 &
|
||||
# User has more than 1 AVD
|
||||
elif [ ${#avd_list[@]} -gt 1 ]
|
||||
then
|
||||
while [ -z ${avd_list[$avd_id]} ]
|
||||
do
|
||||
echo "Choose from one of the following Android Virtual Devices [0 to $((${#avd_list[@]}-1))]:"
|
||||
for(( i = 0 ; i < ${#avd_list[@]} ; i++ ))
|
||||
do
|
||||
echo "$i) ${avd_list[$i]}"
|
||||
done
|
||||
echo -n "> "
|
||||
read avd_id
|
||||
done
|
||||
emulator -cpu-delay 0 -no-boot-anim -cache /tmp/cache -avd ${avd_list[$avd_id]} 1> /dev/null 2>&1 &
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
function clean {
|
||||
ant clean
|
||||
}
|
||||
# has to be used independently and not in conjuction with other commands
|
||||
function log {
|
||||
adb logcat
|
||||
}
|
||||
|
||||
function debug_install {
|
||||
ant debug install
|
||||
}
|
||||
|
||||
function debug {
|
||||
ant debug
|
||||
}
|
||||
|
||||
function launch {
|
||||
local launch_str=$(java -jar $PROJECT_PATH/cordova/appinfo.jar $PROJECT_PATH/AndroidManifest.xml)
|
||||
adb shell am start -n $launch_str
|
||||
}
|
||||
|
||||
function BOOM {
|
||||
clean
|
||||
if [ $(check_devices) == 0 ] ; then
|
||||
debug_install && launch
|
||||
return
|
||||
else
|
||||
debug
|
||||
echo "##################################################################"
|
||||
echo "# Plug in your device or launch an emulator with cordova/emulate #"
|
||||
echo "##################################################################"
|
||||
fi
|
||||
}
|
||||
|
||||
# TODO parse arguments
|
||||
(cd $PROJECT_PATH && $1)
|
||||
15
bin/templates/cordova/cordova.bat
Normal file
@@ -0,0 +1,15 @@
|
||||
@ECHO OFF
|
||||
IF NOT DEFINED JAVA_HOME GOTO MISSING
|
||||
FOR %%X in (java.exe ant.bat android.bat) do (
|
||||
SET FOUND=%%~$PATH:X
|
||||
IF NOT DEFINED FOUND GOTO MISSING
|
||||
)
|
||||
cscript %~dp0\cordova.js %*
|
||||
GOTO END
|
||||
:MISSING
|
||||
ECHO Missing one of the following:
|
||||
ECHO JDK: http://java.oracle.com
|
||||
ECHO Android SDK: http://developer.android.com
|
||||
ECHO Apache ant: http://ant.apache.org
|
||||
EXIT /B 1
|
||||
:END
|
||||
108
bin/templates/cordova/cordova.js
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
var ROOT = WScript.ScriptFullName.split('\\cordova\\cordova.js').join(''),
|
||||
shell=WScript.CreateObject("WScript.Shell");
|
||||
|
||||
function exec(command) {
|
||||
var oExec=shell.Exec(command);
|
||||
var output = new String();
|
||||
while(oExec.Status == 0) {
|
||||
if(!oExec.StdOut.AtEndOfStream) {
|
||||
var line = oExec.StdOut.ReadLine();
|
||||
// XXX: Change to verbose mode
|
||||
//WScript.StdOut.WriteLine(line);
|
||||
output += line;
|
||||
}
|
||||
WScript.sleep(100);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function emulator_running() {
|
||||
var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
|
||||
if(local_devices.match(/emulator/)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function emulate() {
|
||||
// don't run emulator if a device is plugged in or if emulator is already running
|
||||
if(emulator_running()) {
|
||||
WScript.Echo("Device or Emulator already running!");
|
||||
return;
|
||||
}
|
||||
var oExec = shell.Exec("%comspec% /c android.bat list avd");
|
||||
var avd_list = [];
|
||||
var avd_id = -10;
|
||||
while(!oExec.StdOut.AtEndOfStream) {
|
||||
var output = oExec.StdOut.ReadLine();
|
||||
if(output.match(/Name: (.)*/)) {
|
||||
avd_list.push(output.replace(/ *Name:\s/, ""));
|
||||
}
|
||||
}
|
||||
// user has no AVDs
|
||||
if(avd_list.length == 0) {
|
||||
WScript.Echo("You don't have any Android Virtual Devices. Please create at least one AVD.");
|
||||
WScript.Echo("android");
|
||||
WScript.Quit(1);
|
||||
}
|
||||
// user has only one AVD so we launch that one
|
||||
if(avd_list.length == 1) {
|
||||
|
||||
shell.Run("emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\cache -avd "+avd_list[0]);
|
||||
}
|
||||
|
||||
// user has more than one avd so we ask them to choose
|
||||
if(avd_list.length > 1) {
|
||||
while(!avd_list[avd_id]) {
|
||||
WScript.Echo("Choose from one of the following Android Virtual Devices [0 to "+(avd_list.length - 1)+"]:")
|
||||
for(i = 0, j = avd_list.length ; i < j ; i++) {
|
||||
WScript.Echo((i)+") "+avd_list[i]);
|
||||
}
|
||||
WScript.StdOut.Write("> ");
|
||||
avd_id = new Number(WScript.StdIn.ReadLine());
|
||||
}
|
||||
|
||||
shell.Run("emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\\cache -avd "+avd_list[avd_id], 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
function clean() {
|
||||
exec("%comspec% /c ant.bat clean -f "+ROOT+"\\build.xml 2>&1");
|
||||
}
|
||||
|
||||
function debug() {
|
||||
exec("%comspec% /c ant.bat debug -f "+ROOT+"\\build.xml 2>&1");
|
||||
}
|
||||
|
||||
function debug_install() {
|
||||
exec("%comspec% /c ant.bat debug install -f "+ROOT+"\\build.xml 2>&1");
|
||||
}
|
||||
|
||||
function log() {
|
||||
WScript.Echo(exec("%comspec% /c adb.bat logcat"));
|
||||
}
|
||||
|
||||
function launch() {
|
||||
var launch_str=exec("%comspec% /c java -jar "+ROOT+"\\cordova\\appinfo.jar "+ROOT+"\\AndroidManifest.xml");
|
||||
//WScript.Echo(launch_str);
|
||||
exec("%comspec% /c adb shell am start -n "+launch_str+" 2>&1");
|
||||
}
|
||||
|
||||
function BOOM() {
|
||||
clean();
|
||||
if(emulator_running()) {
|
||||
debug_install();
|
||||
launch();
|
||||
} else {
|
||||
debug();
|
||||
WScript.Echo("##################################################################");
|
||||
WScript.Echo("# Plug in your device or launch an emulator with cordova/emulate #");
|
||||
WScript.Echo("##################################################################");
|
||||
}
|
||||
}
|
||||
var args = WScript.Arguments;
|
||||
if(args.count() != 1) {
|
||||
WScript.StdErr.Write("An error has occured!\n");
|
||||
WScript.Quit(1);
|
||||
}
|
||||
eval(args(0)+"()");
|
||||
7
bin/templates/cordova/debug
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
|
||||
|
||||
bash $CORDOVA_PATH/cordova debug
|
||||
1
bin/templates/cordova/debug.bat
Normal file
@@ -0,0 +1 @@
|
||||
%~dp0\cordova.bat debug
|
||||
7
bin/templates/cordova/emulate
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
|
||||
|
||||
bash $CORDOVA_PATH/cordova emulate
|
||||
1
bin/templates/cordova/emulate.bat
Normal file
@@ -0,0 +1 @@
|
||||
%~dp0\cordova.bat emulate
|
||||
7
bin/templates/cordova/log
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
PROJECT_PATH=$( cd "$( dirname "$0" )/.." && pwd )
|
||||
|
||||
bash $PROJECT_PATH/cordova/cordova log
|
||||
@@ -1 +0,0 @@
|
||||
ok...
|
||||
@@ -1,3 +0,0 @@
|
||||
this is local config for cordova stuff to be eventually moved to
|
||||
config.xml ...we think. feedback to @davejohnson/@brianleroux
|
||||
appreciated here!
|
||||
@@ -23,7 +23,7 @@
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<title>PhoneGap</title>
|
||||
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title">
|
||||
<script type="text/javascript" charset="utf-8" src="cordova-1.8.0.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="cordova-1.9.0rc1.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="main.js"></script>
|
||||
|
||||
</head>
|
||||
@@ -1,58 +0,0 @@
|
||||
#! /bin/sh
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
# create a cordova/android project
|
||||
#
|
||||
# USAGE
|
||||
# ./create [path package activity]
|
||||
#
|
||||
|
||||
# load up the config
|
||||
. ./.cordova/config
|
||||
|
||||
PACKAGE_AS_PATH=$(echo $PACKAGE | sed 's/\./\//g')
|
||||
ACTIVITY_PATH=./src/$PACKAGE_AS_PATH/$ACTIVITY.java
|
||||
MANIFEST_PATH=./AndroidManifest.xml
|
||||
|
||||
# create the project
|
||||
android create project --target $TARGET --path . --package $PACKAGE --activity $ACTIVITY
|
||||
|
||||
# copy all the cordova scripts etc in there
|
||||
cp -R ./cordova/templates/project/* .
|
||||
|
||||
# copy in cordova.js
|
||||
cp ./.cordova/android/cordova-$VERSION.js ./assets/www
|
||||
|
||||
# copy in cordova.jar
|
||||
cp ./.cordova/android/cordova-$VERSION.jar ./libs
|
||||
|
||||
# copy in res/xml
|
||||
mkdir ./res/xml
|
||||
cp ./.cordova/android/cordova.xml ./res/xml
|
||||
cp ./.cordova/android/plugins.xml ./res/xml
|
||||
|
||||
# copy in default activity
|
||||
cat ./cordova/templates/Activity.java > $ACTIVITY_PATH
|
||||
|
||||
# interpolate the acivity name and package
|
||||
find "$ACTIVITY_PATH" | xargs grep '__ACTIVITY__' -sl | xargs -L1 sed -i -e "s/__ACTIVITY__/${ACTIVITY}/g"
|
||||
find "$ACTIVITY_PATH" | xargs grep '__ID__' -sl | xargs -L1 sed -i -e "s/__ID__/${PACKAGE}/g"
|
||||
|
||||
find "$MANIFEST_PATH" | xargs grep '__ACTIVITY__' -sl | xargs -L1 sed -i -e "s/__ACTIVITY__/${ACTIVITY}/g"
|
||||
find "$MANIFEST_PATH" | xargs grep '__PACKAGE__' -sl | xargs -L1 sed -i -e "s/__PACKAGE__/${PACKAGE}/g"
|
||||
@@ -1,2 +0,0 @@
|
||||
echo "BALLS"
|
||||
cscript cordova\create.js
|
||||
69
bin/templates/project/cordova/create.js
vendored
@@ -1,69 +0,0 @@
|
||||
var shell=WScript.CreateObject("WScript.Shell");
|
||||
|
||||
function exec(s, output) {
|
||||
WScript.Echo('Executing ' + s);
|
||||
var o=shell.Exec(s);
|
||||
while (o.Status == 0) {
|
||||
WScript.Sleep(100);
|
||||
}
|
||||
WScript.Echo("Command exited with code " + o.Status);
|
||||
}
|
||||
function read(filename) {
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(filename, 1);
|
||||
var s=f.ReadAll();
|
||||
f.Close();
|
||||
return s;
|
||||
}
|
||||
function write(filename, contents) {
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(filename, 2, true);
|
||||
f.Write(contents);
|
||||
f.Close();
|
||||
}
|
||||
function replaceInFile(filename, regexp, replacement) {
|
||||
write(filename, read(filename).replace(regexp, replacement));
|
||||
}
|
||||
|
||||
// working dir
|
||||
var PWD = WScript.ScriptFullName.split('\\cordova\\create.js').join('');
|
||||
|
||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||
var f=fso.OpenTextFile(PWD + '\\.cordova\\config', 1);
|
||||
while (!f.AtEndOfStream) {
|
||||
var prop = f.ReadLine().split('=');
|
||||
var line = 'var ' + prop[0] + '=' + "'" + prop[1] + "';";
|
||||
eval(line); // hacky shit to load config but whatevs
|
||||
}
|
||||
|
||||
var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
|
||||
var ACTIVITY_PATH=PWD+'\\src\\'+PACKAGE_AS_PATH+'\\'+ACTIVITY+'.java';
|
||||
var MANIFEST_PATH=PWD+'\\AndroidManifest.xml';
|
||||
|
||||
exec('android.bat create project --target ' + TARGET + ' --path ' + PWD + ' --package ' + PACKAGE + ' --activity ' + ACTIVITY);
|
||||
|
||||
// copy in activity and other android assets
|
||||
exec('cmd /c xcopy ' + PWD + '\\cordova\\templates\\project\\* ' + PWD +' /Y /S');
|
||||
|
||||
// copy in cordova.js
|
||||
exec('cmd /c copy ' + PWD + '\\.cordova\\android\\cordova-' + VERSION + '.js ' + PWD + '\\assets\\www /Y');
|
||||
|
||||
// copy in cordova.jar
|
||||
exec('cmd /c copy ' + PWD + '\\.cordova\\android\\cordova-' + VERSION + '.jar ' + PWD + '\\libs /Y');
|
||||
|
||||
// copy in res/xml
|
||||
exec('cmd /c md ' + PWD + '\\res\\xml');
|
||||
exec('cmd /c copy ' + PWD + '\\.cordova\\android\\cordova.xml ' + PWD + '\\res\\xml /Y');
|
||||
exec('cmd /c copy ' + PWD + '\\.cordova\\android\\plugins.xml ' + PWD + '\\res\\xml /Y');
|
||||
|
||||
// copy in default activity
|
||||
exec('cmd /c copy ' + PWD + '\\cordova\\templates\\Activity.java ' + ACTIVITY_PATH + ' /Y');
|
||||
|
||||
// interpolate the activity name and package
|
||||
replaceInFile(ACTIVITY_PATH, /__ACTIVITY__/, ACTIVITY);
|
||||
replaceInFile(ACTIVITY_PATH, /__ID__/, PACKAGE);
|
||||
|
||||
replaceInFile(MANIFEST_PATH, /__ACTIVITY__/, ACTIVITY);
|
||||
replaceInFile(MANIFEST_PATH, /__PACKAGE__/, PACKAGE);
|
||||
|
||||
WScript.Echo('Create completed successfully.');
|
||||
@@ -1,27 +0,0 @@
|
||||
#! /bin/sh
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
. ./.cordova/config
|
||||
|
||||
# if there are no devices listed then emulate
|
||||
|
||||
ant clean
|
||||
ant debug install
|
||||
adb shell am start -n $PACKAGE/$PACKAGE.$ACTIVITY
|
||||
@@ -1,31 +0,0 @@
|
||||
#! /bin/sh
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
#Available Android Virtual Devices:
|
||||
# Name: default
|
||||
# Path: /Users/davejohnson/.android/avd/default.avd
|
||||
# Target: Android 2.2 (API level 8)
|
||||
# Skin: WVGA800
|
||||
# Sdcard: 100M
|
||||
|
||||
# get the name of the first virtual device or use command line arg or use "default"
|
||||
|
||||
emulator -cpu-delay 0 -no-boot-anim -cache ./tmp/cache -avd default > /dev/null 2>&1 & # put the avd's chatty ass in the background
|
||||
@@ -1,21 +0,0 @@
|
||||
#! /bin/sh
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
adb logcat
|
||||
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
44
bin/test
@@ -1,44 +0,0 @@
|
||||
#! /bin/sh
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
set -e
|
||||
|
||||
VERSION=$(cat ./VERSION)
|
||||
|
||||
# get the latest mobile-spec
|
||||
git clone git@github.com:callback/callback-test.git
|
||||
|
||||
# clobber test if it exists
|
||||
if [ -e ./test ]
|
||||
then
|
||||
rm -rf ./test
|
||||
fi
|
||||
|
||||
# generate a working proj
|
||||
./bin/create ./test org.apache.cordova.test CordovaTest
|
||||
|
||||
# kill the default app and replace it w/ mobile-spec
|
||||
rm -rf ./test/assets/www
|
||||
mv ./callback-test ./test/assets/www
|
||||
|
||||
# copy in cordova.js since www dir was replaced above
|
||||
cp ./framework/assets/www/cordova-$VERSION.js ./test/assets/www/cordova-$VERSION.js
|
||||
|
||||
# build it, launch it and start logging on stdout
|
||||
cd ./test && ./cordova/debug && ./cordova/log
|
||||
135
bin/tests/test_create_unix.js
Normal file
@@ -0,0 +1,135 @@
|
||||
var build_path = __dirname + '/../..',
|
||||
project_path = '/tmp/example',
|
||||
package_name = 'org.apache.cordova.example',
|
||||
package_as_path = 'org/apache/cordova/example',
|
||||
project_name = 'cordovaExample';
|
||||
|
||||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
util = require('util'),
|
||||
assert = require('assert'),
|
||||
spawn = require('child_process').spawn;
|
||||
|
||||
var version = fs.readFileSync(build_path + '/VERSION').toString().replace('\n', '');
|
||||
|
||||
assert(version !== undefined);
|
||||
assert(version !== '');
|
||||
|
||||
var create_project = spawn(build_path + '/bin/create',
|
||||
[project_path,
|
||||
package_name,
|
||||
project_name]);
|
||||
|
||||
process.on('uncaughtException', function (err) {
|
||||
console.log('Caught exception: ' + err);
|
||||
spawn('rm', ['-rf', project_path], function(code) {
|
||||
if(code != 0) {
|
||||
console.log("Could not delete project directory");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
create_project.on('exit', function(code) {
|
||||
|
||||
assert.equal(code, 0, 'Project did not get created');
|
||||
|
||||
// make sure the project was created
|
||||
path.exists(project_path, function(exists) {
|
||||
assert(exists, 'Project path does not exist');
|
||||
});
|
||||
|
||||
// make sure the build directory was cleaned up
|
||||
// path.exists(build_path + '/framework/libs', function(exists) {
|
||||
// assert(!exists, 'libs directory did not get cleaned up');
|
||||
// });
|
||||
path.exists(build_path + util.format('/framework/assets/cordova-%s.js', version), function(exists) {
|
||||
assert(!exists, 'javascript file did not get cleaned up');
|
||||
});
|
||||
path.exists(build_path + util.format('/framework/cordova-%s.jar', version), function(exists) {
|
||||
assert(!exists, 'jar file did not get cleaned up');
|
||||
});
|
||||
|
||||
// make sure AndroidManifest.xml was added
|
||||
path.exists(util.format('%s/AndroidManifest.xml', project_path), function(exists) {
|
||||
assert(exists, 'AndroidManifest.xml did not get created');
|
||||
// TODO check that the activity name was properly substituted
|
||||
});
|
||||
|
||||
// make sure main Activity was added
|
||||
path.exists(util.format('%s/src/%s/%s.java', project_path, package_as_path, project_name), function(exists) {
|
||||
assert(exists, 'Activity did not get created');
|
||||
// TODO check that package name and activity name were substitued properly
|
||||
});
|
||||
|
||||
// make sure plugins.xml was added
|
||||
path.exists(util.format('%s/res/xml/plugins.xml', project_path), function(exists) {
|
||||
assert(exists, 'plugins.xml did not get created');
|
||||
});
|
||||
|
||||
// make sure cordova.xml was added
|
||||
path.exists(util.format('%s/res/xml/cordova.xml', project_path), function(exists) {
|
||||
assert(exists, 'plugins.xml did not get created');
|
||||
});
|
||||
|
||||
// make sure cordova.jar was added
|
||||
path.exists(util.format('%s/libs/cordova-%s.jar', project_path, version), function(exists) {
|
||||
assert(exists, 'cordova.jar did not get added');
|
||||
});
|
||||
|
||||
// make sure cordova.js was added
|
||||
path.exists(util.format('%s/assets/www/cordova-%s.js', project_path, version), function(exists) {
|
||||
assert(exists, 'cordova.js did not get added');
|
||||
});
|
||||
|
||||
// make sure cordova master script was added
|
||||
path.exists(util.format('%s/cordova/cordova', project_path), function(exists) {
|
||||
assert(exists, 'cordova script did not get added');
|
||||
});
|
||||
|
||||
// make sure debug script was added
|
||||
path.exists(util.format('%s/cordova/debug', project_path), function(exists) {
|
||||
assert(exists, 'debug script did not get added');
|
||||
});
|
||||
|
||||
// make sure BOOM script was added
|
||||
path.exists(util.format('%s/cordova/BOOM', project_path), function(exists) {
|
||||
assert(exists, 'BOOM script did not get added');
|
||||
});
|
||||
|
||||
// make sure log script was added
|
||||
path.exists(util.format('%s/cordova/log', project_path), function(exists) {
|
||||
assert(exists, 'log script did not get added');
|
||||
});
|
||||
|
||||
// make sure clean script was added
|
||||
path.exists(util.format('%s/cordova/clean', project_path), function(exists) {
|
||||
assert(exists, 'clean script did not get added');
|
||||
});
|
||||
|
||||
// make sure emulate script was added
|
||||
path.exists(util.format('%s/cordova/emulate', project_path), function(exists) {
|
||||
assert(exists, 'emulate script did not get added');
|
||||
});
|
||||
|
||||
// make sure appinfo.jar script was added
|
||||
path.exists(util.format('%s/cordova/appinfo.jar', project_path), function(exists) {
|
||||
assert(exists, 'appinfo.jar script did not get added');
|
||||
});
|
||||
|
||||
// check that project compiles && creates a cordovaExample-debug.apk
|
||||
var compile_project = spawn('ant', ['debug'], {cwd: project_path});
|
||||
|
||||
compile_project.on('exit', function(code) {
|
||||
assert.equal(code, 0, 'Cordova Android Project does not compile');
|
||||
// make sure cordovaExample-debug.apk was created
|
||||
path.exists(util.format('%s/bin/%s-debug.apk', project_path, project_name), function(exists) {
|
||||
assert(exists, 'Package did not get created');
|
||||
|
||||
// if project compiles properly just AXE it
|
||||
spawn('rm', ['-rf', project_path], function(code) {
|
||||
assert.equal(code, 0, 'Could not remove project directory');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
143
bin/tests/test_create_win.js
Normal file
@@ -0,0 +1,143 @@
|
||||
var build_path = __dirname + '/../..'
|
||||
project_path = process.env.Temp + '\\example',
|
||||
package_name = 'org.apache.cordova.example',
|
||||
package_as_path = 'org/apache/cordova/example',
|
||||
project_name = 'cordovaExample';
|
||||
|
||||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
util = require('util'),
|
||||
assert = require('assert'),
|
||||
exec = require('child_process').exec,
|
||||
spawn = require('child_process').spawn;
|
||||
|
||||
var version = fs.readFileSync(build_path + '/VERSION').toString().replace('\r\n', '');
|
||||
|
||||
assert(version !== undefined);
|
||||
assert(version !== '');
|
||||
|
||||
process.on('uncaughtException', function (err) {
|
||||
console.log('Caught exception: ' + err);
|
||||
exec('rd /s /q ' + project_path);
|
||||
});
|
||||
|
||||
var create_project = spawn('cscript',
|
||||
[build_path + '/bin/create.js',
|
||||
project_path,
|
||||
package_name,
|
||||
project_name]
|
||||
);
|
||||
|
||||
create_project.stderr.on('data', function (data) {
|
||||
console.log('ps stderr: ' + data);
|
||||
});
|
||||
|
||||
create_project.stderr.on('data', function(data) {
|
||||
console.log(data.toString());
|
||||
});
|
||||
|
||||
create_project.stdout.on('data', function(data) {
|
||||
console.log(data.toString());
|
||||
});
|
||||
|
||||
create_project.on('exit', function(code) {
|
||||
assert.equal(code, 0, 'Project did not get created');
|
||||
|
||||
// make sure the project was created
|
||||
path.exists(project_path, function(exists) {
|
||||
assert(exists, 'Project path does not exist');
|
||||
});
|
||||
|
||||
// make sure the build directory was cleaned up
|
||||
// path.exists(build_path + '/framework/libs', function(exists) {
|
||||
// assert(!exists, 'libs directory did not get cleaned up');
|
||||
// });
|
||||
path.exists(build_path + util.format('/framework/assets/cordova-%s.js', version), function(exists) {
|
||||
assert(!exists, 'javascript file did not get cleaned up');
|
||||
});
|
||||
path.exists(build_path + util.format('/framework/cordova-%s.jar', version), function(exists) {
|
||||
assert(!exists, 'jar file did not get cleaned up');
|
||||
});
|
||||
|
||||
// make sure AndroidManifest.xml was added
|
||||
path.exists(util.format('%s/AndroidManifest.xml', project_path), function(exists) {
|
||||
assert(exists, 'AndroidManifest.xml did not get created');
|
||||
// TODO check that the activity name was properly substituted
|
||||
});
|
||||
|
||||
// make sure main Activity was added
|
||||
path.exists(util.format('%s/src/%s/%s.java', project_path, package_as_path, project_name), function(exists) {
|
||||
assert(exists, 'Activity did not get created');
|
||||
// TODO check that package name and activity name were substitued properly
|
||||
});
|
||||
|
||||
// make sure plugins.xml was added
|
||||
path.exists(util.format('%s/res/xml/plugins.xml', project_path), function(exists) {
|
||||
assert(exists, 'plugins.xml did not get created');
|
||||
});
|
||||
|
||||
// make sure cordova.xml was added
|
||||
path.exists(util.format('%s/res/xml/cordova.xml', project_path), function(exists) {
|
||||
assert(exists, 'plugins.xml did not get created');
|
||||
});
|
||||
|
||||
// make sure cordova.jar was added
|
||||
path.exists(util.format('%s/libs/cordova-%s.jar', project_path, version), function(exists) {
|
||||
assert(exists, 'cordova.jar did not get added');
|
||||
});
|
||||
|
||||
// make sure cordova.js was added
|
||||
path.exists(util.format('%s/assets/www/cordova-%s.js', project_path, version), function(exists) {
|
||||
assert(exists, 'cordova.js did not get added');
|
||||
});
|
||||
|
||||
// make sure cordova master script was added
|
||||
path.exists(util.format('%s/cordova/cordova.bat', project_path), function(exists) {
|
||||
assert(exists, 'cordova script did not get added');
|
||||
});
|
||||
|
||||
// make sure debug script was added
|
||||
path.exists(util.format('%s/cordova/debug.bat', project_path), function(exists) {
|
||||
assert(exists, 'debug script did not get added');
|
||||
});
|
||||
|
||||
// make sure BOOM script was added
|
||||
path.exists(util.format('%s/cordova/BOOM.bat', project_path), function(exists) {
|
||||
assert(exists, 'BOOM script did not get added');
|
||||
});
|
||||
|
||||
// make sure log script was added
|
||||
path.exists(util.format('%s/cordova/log.bat', project_path), function(exists) {
|
||||
assert(exists, 'log script did not get added');
|
||||
});
|
||||
|
||||
// make sure clean script was added
|
||||
path.exists(util.format('%s/cordova/clean.bat', project_path), function(exists) {
|
||||
assert(exists, 'clean script did not get added');
|
||||
});
|
||||
|
||||
// make sure emulate script was added
|
||||
path.exists(util.format('%s/cordova/emulate.bat', project_path), function(exists) {
|
||||
assert(exists, 'emulate script did not get added');
|
||||
});
|
||||
|
||||
// make sure appinfo.jar script was added
|
||||
path.exists(util.format('%s/cordova/appinfo.jar', project_path), function(exists) {
|
||||
assert(exists, 'appinfo.jar script did not get added');
|
||||
});
|
||||
|
||||
// check that project compiles && creates a cordovaExample-debug.apk
|
||||
// XXX: !@##!@# WINDOWS
|
||||
exec('ant debug -f ' + project_path + "\\build.xml", function(error, stdout, stderr) {
|
||||
assert(error == null, "Cordova Android Project does not compile");
|
||||
path.exists(util.format('%s/bin/%s-debug.apk', project_path, project_name),
|
||||
function(exists) {
|
||||
assert(exists, 'Package did not get created');
|
||||
// if project compiles properly just AXE it
|
||||
exec('rd /s /q ' + project_path);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>Cordova</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
<name>Cordova</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<!--
|
||||
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
|
||||
@@ -39,12 +39,12 @@
|
||||
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
|
||||
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="org.apache.cordova.DroidGap" android:label="@string/app_name"
|
||||
<activity android:name="org.apache.cordova.DroidGap" android:label="@string/app_name"
|
||||
android:configChanges="orientation|keyboardHidden">
|
||||
<intent-filter>
|
||||
</intent-filter>
|
||||
@@ -65,4 +65,4 @@
|
||||
</application>
|
||||
|
||||
<uses-sdk android:minSdkVersion="2" />
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// commit ac0a3990438f4a89faa993316fb5614f61cf3be6
|
||||
// commit 25033fceac7c800623f1f16881b784d19eba69cc
|
||||
|
||||
// File generated at :: Tue Jun 05 2012 14:14:16 GMT-0700 (PDT)
|
||||
// File generated at :: Thu Jun 21 2012 10:45:32 GMT-0700 (PDT)
|
||||
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
@@ -190,7 +190,9 @@ var cordova = {
|
||||
fireDocumentEvent: function(type, data) {
|
||||
var evt = createEvent(type, data);
|
||||
if (typeof documentEventHandlers[type] != 'undefined') {
|
||||
documentEventHandlers[type].fire(evt);
|
||||
setTimeout(function() {
|
||||
documentEventHandlers[type].fire(evt);
|
||||
}, 0);
|
||||
} else {
|
||||
document.dispatchEvent(evt);
|
||||
}
|
||||
@@ -198,7 +200,9 @@ var cordova = {
|
||||
fireWindowEvent: function(type, data) {
|
||||
var evt = createEvent(type,data);
|
||||
if (typeof windowEventHandlers[type] != 'undefined') {
|
||||
windowEventHandlers[type].fire(evt);
|
||||
setTimeout(function() {
|
||||
windowEventHandlers[type].fire(evt);
|
||||
}, 0);
|
||||
} else {
|
||||
window.dispatchEvent(evt);
|
||||
}
|
||||
@@ -953,8 +957,7 @@ module.exports = function(success, fail, service, action, args) {
|
||||
|
||||
// If a result was returned
|
||||
if (r.length > 0) {
|
||||
var v;
|
||||
eval("v="+r+";");
|
||||
var v = JSON.parse(r);
|
||||
|
||||
// If status is OK, then return value back to caller
|
||||
if (v.status === cordova.callbackStatus.OK) {
|
||||
@@ -1284,6 +1287,10 @@ cameraExport.getPicture = function(successCallback, errorCallback, options) {
|
||||
exec(successCallback, errorCallback, "Camera", "takePicture", [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType, mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions]);
|
||||
};
|
||||
|
||||
cameraExport.cleanup = function(successCallback, errorCallback) {
|
||||
exec(successCallback, errorCallback, "Camera", "cleanup", []);
|
||||
};
|
||||
|
||||
module.exports = cameraExport;
|
||||
});
|
||||
|
||||
@@ -2591,6 +2598,8 @@ var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
|
||||
var FileSystem = function(name, root) {
|
||||
this.name = name || null;
|
||||
if (root) {
|
||||
console.log('root.name ' + name);
|
||||
console.log('root.root ' + root);
|
||||
this.root = new DirectoryEntry(root.name, root.fullPath);
|
||||
}
|
||||
};
|
||||
@@ -2600,7 +2609,8 @@ module.exports = FileSystem;
|
||||
|
||||
// file: lib/common/plugin/FileTransfer.js
|
||||
define("cordova/plugin/FileTransfer", function(require, exports, module) {
|
||||
var exec = require('cordova/exec');
|
||||
var exec = require('cordova/exec'),
|
||||
FileTransferError = require('cordova/plugin/FileTransferError');
|
||||
|
||||
/**
|
||||
* FileTransfer uploads a file to a remote server.
|
||||
@@ -2619,6 +2629,8 @@ var FileTransfer = function() {};
|
||||
* @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
|
||||
*/
|
||||
FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) {
|
||||
// sanity parameter checking
|
||||
if (!filePath || !server) throw new Error("FileTransfer.upload requires filePath and server URL parameters at the minimum.");
|
||||
// check for options
|
||||
var fileKey = null;
|
||||
var fileName = null;
|
||||
@@ -2640,7 +2652,12 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
|
||||
}
|
||||
}
|
||||
|
||||
exec(successCallback, errorCallback, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode]);
|
||||
var fail = function(e) {
|
||||
var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
|
||||
errorCallback(error);
|
||||
};
|
||||
|
||||
exec(successCallback, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode]);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2651,6 +2668,8 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
|
||||
* @param errorCallback {Function} Callback to be invoked upon error
|
||||
*/
|
||||
FileTransfer.prototype.download = function(source, target, successCallback, errorCallback) {
|
||||
// sanity parameter checking
|
||||
if (!source || !target) throw new Error("FileTransfer.download requires source URI and target URI parameters at the minimum.");
|
||||
var win = function(result) {
|
||||
var entry = null;
|
||||
if (result.isDirectory) {
|
||||
@@ -2665,6 +2684,12 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
|
||||
entry.fullPath = result.fullPath;
|
||||
successCallback(entry);
|
||||
};
|
||||
|
||||
var fail = function(e) {
|
||||
var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
|
||||
errorCallback(error);
|
||||
};
|
||||
|
||||
exec(win, errorCallback, 'FileTransfer', 'download', [source, target]);
|
||||
};
|
||||
|
||||
@@ -2678,8 +2703,11 @@ define("cordova/plugin/FileTransferError", function(require, exports, module) {
|
||||
* FileTransferError
|
||||
* @constructor
|
||||
*/
|
||||
var FileTransferError = function(code) {
|
||||
var FileTransferError = function(code, source, target, status) {
|
||||
this.code = code || null;
|
||||
this.source = source || null;
|
||||
this.target = target || null;
|
||||
this.http_status = status || null;
|
||||
};
|
||||
|
||||
FileTransferError.FILE_NOT_FOUND_ERR = 1;
|
||||
@@ -2687,6 +2715,7 @@ FileTransferError.INVALID_URL_ERR = 2;
|
||||
FileTransferError.CONNECTION_ERR = 3;
|
||||
|
||||
module.exports = FileTransferError;
|
||||
|
||||
});
|
||||
|
||||
// file: lib/common/plugin/FileUploadOptions.js
|
||||
@@ -5466,6 +5495,9 @@ define("cordova/plugin/splashscreen", function(require, exports, module) {
|
||||
var exec = require('cordova/exec');
|
||||
|
||||
var splashscreen = {
|
||||
show:function() {
|
||||
exec(null, null, "SplashScreen", "show", []);
|
||||
},
|
||||
hide:function() {
|
||||
exec(null, null, "SplashScreen", "hide", []);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!--
|
||||
<!--
|
||||
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
|
||||
@@ -19,7 +19,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<script src="cordova-1.8.0.js"></script>
|
||||
<script src="cordova-1.9.0rc1.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
<!--
|
||||
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
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
|
||||
<!-- We need to setup the double quote. -->
|
||||
<property name="dblQuote">"</property>
|
||||
|
||||
@@ -110,10 +110,10 @@
|
||||
|
||||
<!-- Combine JavaScript files into one cordova-uncompressed.js file. -->
|
||||
<target name="build-javascript" depends="clean">
|
||||
|
||||
|
||||
<!-- Clean up existing files -->
|
||||
<!--<delete file="assets/www/cordova_${version}.js"/>-->
|
||||
|
||||
|
||||
<!-- Create uncompressed JS file -->
|
||||
<concat destfile="assets/www/cordova-${version}.js">
|
||||
<filelist dir="assets/js" files="cordova.android.js"/>
|
||||
@@ -121,8 +121,8 @@
|
||||
|
||||
<!-- update project files to reference cordova-x.x.x.min.js -->
|
||||
<replaceregexp match="cordova(.*)\.js" replace="cordova-${version}.js" byline="true">
|
||||
<fileset file="assets/www/index.html" />
|
||||
<fileset file="../bin/templates/project/cordova/templates/project/assets/www/index.html" />
|
||||
<fileset file="assets/www/index.html" />
|
||||
<fileset file="../bin/templates/project/assets/www/index.html" />
|
||||
</replaceregexp>
|
||||
|
||||
<!-- This is sketchy, but it works, ${dblQuote} does not -->
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "build.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<!--
|
||||
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
|
||||
@@ -21,9 +21,9 @@
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
>
|
||||
<WebView android:id="@+id/appView"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="fill_parent"
|
||||
/>
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<!--
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<!--
|
||||
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
|
||||
@@ -18,19 +18,19 @@
|
||||
under the License.
|
||||
-->
|
||||
<cordova>
|
||||
<!--
|
||||
access elements control the Android whitelist.
|
||||
Domains are assumed blocked unless set otherwise
|
||||
-->
|
||||
<!--
|
||||
access elements control the Android whitelist.
|
||||
Domains are assumed blocked unless set otherwise
|
||||
-->
|
||||
|
||||
<access origin="http://127.0.0.1*"/> <!-- allow local pages -->
|
||||
|
||||
<!-- <access origin="https://example.com" /> allow any secure requests to example.com -->
|
||||
<!-- <access origin="https://example.com" subdomains="true" /> such as above, but including subdomains, such as www -->
|
||||
<!-- <access origin=".*"/> Allow all domains, suggested development use only -->
|
||||
<!-- <access origin="https://example.com" /> allow any secure requests to example.com -->
|
||||
<!-- <access origin="https://example.com" subdomains="true" /> such as above, but including subdomains, such as www -->
|
||||
<!-- <access origin=".*"/> Allow all domains, suggested development use only -->
|
||||
|
||||
<log level="DEBUG"/>
|
||||
<preference name="classicRender" value="true" />
|
||||
<preference name="useBrowserHistory" value="false" />
|
||||
</cordova>
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<!--
|
||||
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
|
||||
|
||||
@@ -20,7 +20,7 @@ package com.phonegap.api;
|
||||
|
||||
/**
|
||||
* Log to Android logging system.
|
||||
*
|
||||
*
|
||||
* Log message can be a string or a printf formatted string with arguments.
|
||||
* See http://developer.android.com/reference/java/util/Formatter.html
|
||||
*/
|
||||
|
||||
@@ -18,19 +18,20 @@
|
||||
*/
|
||||
package com.phonegap.api;
|
||||
|
||||
import org.apache.cordova.CordovaWebView;
|
||||
import org.apache.cordova.api.CordovaInterface;
|
||||
|
||||
import android.webkit.WebView;
|
||||
|
||||
/**
|
||||
* PluginManager is exposed to JavaScript in the Cordova WebView.
|
||||
*
|
||||
*
|
||||
* Calling native plugin code can be done by calling PluginManager.exec(...)
|
||||
* from JavaScript.
|
||||
*/
|
||||
public class PluginManager extends org.apache.cordova.api.PluginManager {
|
||||
|
||||
public PluginManager(WebView app, CordovaInterface ctx) {
|
||||
super(app, ctx);
|
||||
public PluginManager(WebView app, CordovaInterface ctx) throws Exception {
|
||||
super((CordovaWebView) app, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,32 +22,32 @@ import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class PluginResult extends org.apache.cordova.api.PluginResult {
|
||||
|
||||
public PluginResult(Status status) {
|
||||
super(status);
|
||||
}
|
||||
|
||||
public PluginResult(Status status, String message) {
|
||||
super(status, message);
|
||||
}
|
||||
|
||||
public PluginResult(Status status, JSONArray message) {
|
||||
public PluginResult(Status status) {
|
||||
super(status);
|
||||
}
|
||||
|
||||
public PluginResult(Status status, String message) {
|
||||
super(status, message);
|
||||
}
|
||||
}
|
||||
|
||||
public PluginResult(Status status, JSONObject message) {
|
||||
public PluginResult(Status status, JSONArray message) {
|
||||
super(status, message);
|
||||
}
|
||||
}
|
||||
|
||||
public PluginResult(Status status, int i) {
|
||||
public PluginResult(Status status, JSONObject message) {
|
||||
super(status, message);
|
||||
}
|
||||
|
||||
public PluginResult(Status status, int i) {
|
||||
super(status, i);
|
||||
}
|
||||
}
|
||||
|
||||
public PluginResult(Status status, float f) {
|
||||
public PluginResult(Status status, float f) {
|
||||
super(status, f);
|
||||
}
|
||||
}
|
||||
|
||||
public PluginResult(Status status, boolean b) {
|
||||
public PluginResult(Status status, boolean b) {
|
||||
super(status, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
*/
|
||||
package org.apache.cordova;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cordova.api.CordovaInterface;
|
||||
import org.apache.cordova.api.Plugin;
|
||||
import org.apache.cordova.api.PluginResult;
|
||||
@@ -31,17 +26,14 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.location.Location;
|
||||
import android.util.Log;
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* This class listens to the accelerometer sensor and stores the latest
|
||||
* This class listens to the accelerometer sensor and stores the latest
|
||||
* acceleration values x,y,z.
|
||||
*/
|
||||
public class AccelListener extends Plugin implements SensorEventListener {
|
||||
@@ -50,14 +42,14 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
||||
public static int STARTING = 1;
|
||||
public static int RUNNING = 2;
|
||||
public static int ERROR_FAILED_TO_START = 3;
|
||||
|
||||
private float x,y,z; // most recent acceleration values
|
||||
private long timestamp; // time of most recent value
|
||||
private int status; // status of listener
|
||||
|
||||
private float x,y,z; // most recent acceleration values
|
||||
private long timestamp; // time of most recent value
|
||||
private int status; // status of listener
|
||||
private int accuracy = SensorManager.SENSOR_STATUS_UNRELIABLE;
|
||||
|
||||
private SensorManager sensorManager; // Sensor manager
|
||||
private Sensor mSensor; // Acceleration sensor returned by sensor manager
|
||||
private Sensor mSensor; // Acceleration sensor returned by sensor manager
|
||||
|
||||
private String callbackId; // Keeps track of the single "start" callback ID passed in from JS
|
||||
|
||||
@@ -71,31 +63,32 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
||||
this.timestamp = 0;
|
||||
this.setStatus(AccelListener.STOPPED);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*
|
||||
* @param cordova The context of the main Activity.
|
||||
*/
|
||||
public void setContext(CordovaInterface ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
|
||||
|
||||
public void setContext(CordovaInterface cordova) {
|
||||
super.setContext(cordova);
|
||||
this.sensorManager = (SensorManager) cordova.getActivity().getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.NO_RESULT;
|
||||
String message = "";
|
||||
PluginResult result = new PluginResult(status, message);
|
||||
result.setKeepCallback(true);
|
||||
result.setKeepCallback(true);
|
||||
|
||||
if (action.equals("start")) {
|
||||
this.callbackId = callbackId;
|
||||
@@ -115,7 +108,7 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by AccelBroker when listener is to be shut down.
|
||||
* Stop listener.
|
||||
@@ -131,45 +124,45 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
||||
/**
|
||||
* Start listening for acceleration sensor.
|
||||
*
|
||||
* @return status of listener
|
||||
*/
|
||||
* @return status of listener
|
||||
*/
|
||||
private int start() {
|
||||
// If already starting or running, then just return
|
||||
if ((this.status == AccelListener.RUNNING) || (this.status == AccelListener.STARTING)) {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
this.setStatus(AccelListener.STARTING);
|
||||
|
||||
// Get accelerometer from sensor manager
|
||||
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
|
||||
// If already starting or running, then just return
|
||||
if ((this.status == AccelListener.RUNNING) || (this.status == AccelListener.STARTING)) {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
// If found, then register as listener
|
||||
if ((list != null) && (list.size() > 0)) {
|
||||
this.setStatus(AccelListener.STARTING);
|
||||
|
||||
// Get accelerometer from sensor manager
|
||||
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
|
||||
|
||||
// If found, then register as listener
|
||||
if ((list != null) && (list.size() > 0)) {
|
||||
this.mSensor = list.get(0);
|
||||
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_UI);
|
||||
this.setStatus(AccelListener.STARTING);
|
||||
} else {
|
||||
} else {
|
||||
this.setStatus(AccelListener.ERROR_FAILED_TO_START);
|
||||
this.fail(AccelListener.ERROR_FAILED_TO_START, "No sensors found to register accelerometer listening to.");
|
||||
return this.status;
|
||||
}
|
||||
|
||||
// Wait until running
|
||||
long timeout = 2000;
|
||||
while ((this.status == STARTING) && (timeout > 0)) {
|
||||
}
|
||||
|
||||
// Wait until running
|
||||
long timeout = 2000;
|
||||
while ((this.status == STARTING) && (timeout > 0)) {
|
||||
timeout = timeout - 100;
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (timeout == 0) {
|
||||
}
|
||||
if (timeout == 0) {
|
||||
this.setStatus(AccelListener.ERROR_FAILED_TO_START);
|
||||
this.fail(AccelListener.ERROR_FAILED_TO_START, "Accelerometer could not be started.");
|
||||
}
|
||||
return this.status;
|
||||
}
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,16 +178,16 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
||||
|
||||
/**
|
||||
* Called when the accuracy of the sensor has changed.
|
||||
*
|
||||
*
|
||||
* @param sensor
|
||||
* @param accuracy
|
||||
*/
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// Only look at accelerometer events
|
||||
// Only look at accelerometer events
|
||||
if (sensor.getType() != Sensor.TYPE_ACCELEROMETER) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If not running, then just return
|
||||
if (this.status == AccelListener.STOPPED) {
|
||||
return;
|
||||
@@ -204,7 +197,7 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
||||
|
||||
/**
|
||||
* Sensor listener event.
|
||||
*
|
||||
*
|
||||
* @param SensorEvent event
|
||||
*/
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
@@ -212,14 +205,13 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
||||
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If not running, then just return
|
||||
if (this.status == AccelListener.STOPPED) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setStatus(AccelListener.RUNNING);
|
||||
|
||||
|
||||
if (this.accuracy >= SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM) {
|
||||
|
||||
// Save time that event was received
|
||||
@@ -247,7 +239,7 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
||||
|
||||
this.error(err, this.callbackId);
|
||||
}
|
||||
|
||||
|
||||
private void win() {
|
||||
// Success return object
|
||||
PluginResult result = new PluginResult(PluginResult.Status.OK, this.getAccelerationJSON());
|
||||
@@ -259,7 +251,6 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
||||
private void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
private JSONObject getAccelerationJSON() {
|
||||
JSONObject r = new JSONObject();
|
||||
try {
|
||||
|
||||
@@ -45,30 +45,36 @@ public class App extends Plugin {
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("clearCache")) {
|
||||
this.clearCache();
|
||||
}
|
||||
else if (action.equals("loadUrl")) {
|
||||
this.loadUrl(args.getString(0), args.optJSONObject(1));
|
||||
if (action.equals("clearCache")) {
|
||||
this.clearCache();
|
||||
}
|
||||
else if (action.equals("cancelLoadUrl")) {
|
||||
this.cancelLoadUrl();
|
||||
else if (action.equals("show")) { // TODO @bc - Not in master branch. When should this be called?
|
||||
cordova.getActivity().runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
webView.postMessage("spinner", "stop");
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (action.equals("clearHistory")) {
|
||||
this.clearHistory();
|
||||
else if (action.equals("loadUrl")) {
|
||||
this.loadUrl(args.getString(0), args.optJSONObject(1));
|
||||
}
|
||||
else if (action.equals("cancelLoadUrl")) {
|
||||
this.cancelLoadUrl();
|
||||
}
|
||||
else if (action.equals("clearHistory")) {
|
||||
this.clearHistory();
|
||||
}
|
||||
else if (action.equals("backHistory")) {
|
||||
this.backHistory();
|
||||
}
|
||||
else if (action.equals("overrideBackbutton")) {
|
||||
this.overrideBackbutton(args.getBoolean(0));
|
||||
else if (action.equals("overrideButton")) {
|
||||
this.overrideButton(args.getString(0), args.getBoolean(1));
|
||||
}
|
||||
else if (action.equals("isBackbuttonOverridden")) {
|
||||
boolean b = this.isBackbuttonOverridden();
|
||||
return new PluginResult(status, b);
|
||||
else if (action.equals("overrideBackbutton")) {
|
||||
this.overrideBackbutton(args.getBoolean(0));
|
||||
}
|
||||
else if (action.equals("exitApp")) {
|
||||
this.exitApp();
|
||||
else if (action.equals("exitApp")) {
|
||||
this.exitApp();
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
@@ -80,119 +86,124 @@ public class App extends Plugin {
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clear the resource cache.
|
||||
*/
|
||||
public void clearCache() {
|
||||
((DroidGap)this.ctx).clearCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the url into the webview.
|
||||
*
|
||||
* @param url
|
||||
* @param props Properties that can be passed in to the DroidGap activity (i.e. loadingDialog, wait, ...)
|
||||
* @throws JSONException
|
||||
*/
|
||||
public void loadUrl(String url, JSONObject props) throws JSONException {
|
||||
LOG.d("App", "App.loadUrl("+url+","+props+")");
|
||||
int wait = 0;
|
||||
boolean openExternal = false;
|
||||
boolean clearHistory = false;
|
||||
/**
|
||||
* Clear the resource cache.
|
||||
*/
|
||||
public void clearCache() {
|
||||
this.webView.clearCache(true);
|
||||
}
|
||||
|
||||
// If there are properties, then set them on the Activity
|
||||
HashMap<String, Object> params = new HashMap<String, Object>();
|
||||
if (props != null) {
|
||||
JSONArray keys = props.names();
|
||||
for (int i=0; i<keys.length(); i++) {
|
||||
String key = keys.getString(i);
|
||||
if (key.equals("wait")) {
|
||||
wait = props.getInt(key);
|
||||
}
|
||||
else if (key.equalsIgnoreCase("openexternal")) {
|
||||
openExternal = props.getBoolean(key);
|
||||
}
|
||||
else if (key.equalsIgnoreCase("clearhistory")) {
|
||||
clearHistory = props.getBoolean(key);
|
||||
}
|
||||
else {
|
||||
Object value = props.get(key);
|
||||
if (value == null) {
|
||||
/**
|
||||
* Load the url into the webview.
|
||||
*
|
||||
* @param url
|
||||
* @param props Properties that can be passed in to the DroidGap activity (i.e. loadingDialog, wait, ...)
|
||||
* @throws JSONException
|
||||
*/
|
||||
public void loadUrl(String url, JSONObject props) throws JSONException {
|
||||
LOG.d("App", "App.loadUrl("+url+","+props+")");
|
||||
int wait = 0;
|
||||
boolean openExternal = false;
|
||||
boolean clearHistory = false;
|
||||
|
||||
}
|
||||
else if (value.getClass().equals(String.class)) {
|
||||
params.put(key, (String)value);
|
||||
}
|
||||
else if (value.getClass().equals(Boolean.class)) {
|
||||
params.put(key, (Boolean)value);
|
||||
}
|
||||
else if (value.getClass().equals(Integer.class)) {
|
||||
params.put(key, (Integer)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If there are properties, then set them on the Activity
|
||||
HashMap<String, Object> params = new HashMap<String, Object>();
|
||||
if (props != null) {
|
||||
JSONArray keys = props.names();
|
||||
for (int i = 0; i < keys.length(); i++) {
|
||||
String key = keys.getString(i);
|
||||
if (key.equals("wait")) {
|
||||
wait = props.getInt(key);
|
||||
}
|
||||
else if (key.equalsIgnoreCase("openexternal")) {
|
||||
openExternal = props.getBoolean(key);
|
||||
}
|
||||
else if (key.equalsIgnoreCase("clearhistory")) {
|
||||
clearHistory = props.getBoolean(key);
|
||||
}
|
||||
else {
|
||||
Object value = props.get(key);
|
||||
if (value == null) {
|
||||
|
||||
// If wait property, then delay loading
|
||||
}
|
||||
else if (value.getClass().equals(String.class)) {
|
||||
params.put(key, (String)value);
|
||||
}
|
||||
else if (value.getClass().equals(Boolean.class)) {
|
||||
params.put(key, (Boolean)value);
|
||||
}
|
||||
else if (value.getClass().equals(Integer.class)) {
|
||||
params.put(key, (Integer)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wait > 0) {
|
||||
try {
|
||||
synchronized(this) {
|
||||
this.wait(wait);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
((DroidGap)this.ctx).showWebPage(url, openExternal, clearHistory, params);
|
||||
}
|
||||
// If wait property, then delay loading
|
||||
|
||||
if (wait > 0) {
|
||||
try {
|
||||
synchronized(this) {
|
||||
this.wait(wait);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
this.webView.showWebPage(url, openExternal, clearHistory, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel loadUrl before it has been loaded (Only works on a CordovaInterface class)
|
||||
*/
|
||||
@Deprecated
|
||||
public void cancelLoadUrl() {
|
||||
this.cordova.cancelLoadUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel loadUrl before it has been loaded.
|
||||
*/
|
||||
public void cancelLoadUrl() {
|
||||
((DroidGap)this.ctx).cancelLoadUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear page history for the app.
|
||||
*/
|
||||
public void clearHistory() {
|
||||
((DroidGap)this.ctx).clearHistory();
|
||||
this.webView.clearHistory();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Go to previous page displayed.
|
||||
* This is the same as pressing the backbutton on Android device.
|
||||
*/
|
||||
public void backHistory() {
|
||||
((DroidGap)this.ctx).backHistory();
|
||||
this.webView.backHistory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default behavior of the Android back button.
|
||||
* If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
|
||||
*
|
||||
*
|
||||
* @param override T=override, F=cancel override
|
||||
*/
|
||||
public void overrideBackbutton(boolean override) {
|
||||
LOG.i("DroidGap", "WARNING: Back Button Default Behaviour will be overridden. The backbutton event will be fired!");
|
||||
((DroidGap)this.ctx).bound = override;
|
||||
LOG.i("App", "WARNING: Back Button Default Behaviour will be overridden. The backbutton event will be fired!");
|
||||
webView.bindButton(override);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the Android back button is overridden by the user.
|
||||
*
|
||||
* @return boolean
|
||||
* Override the default behavior of the Android volume buttons.
|
||||
* If overridden, when the volume button is pressed, the "volume[up|down]button" JavaScript event will be fired.
|
||||
*
|
||||
* @param button volumeup, volumedown
|
||||
* @param override T=override, F=cancel override
|
||||
*/
|
||||
public boolean isBackbuttonOverridden() {
|
||||
return ((DroidGap)this.ctx).bound;
|
||||
public void overrideButton(String button, boolean override) {
|
||||
LOG.i("DroidGap", "WARNING: Volume Button Default Behaviour will be overridden. The volume event will be fired!");
|
||||
webView.bindButton(button, override);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit the Android application.
|
||||
*/
|
||||
public void exitApp() {
|
||||
((DroidGap)this.ctx).endActivity();
|
||||
this.webView.postMessage("exit", null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,22 +22,19 @@ import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apache.cordova.api.LOG;
|
||||
import org.apache.cordova.api.Plugin;
|
||||
import org.apache.cordova.api.PluginResult;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* This class called by CordovaActivity to play and record audio.
|
||||
* This class called by CordovaActivity to play and record audio.
|
||||
* The file can be local or over a network using http.
|
||||
*
|
||||
*
|
||||
* Audio formats supported (tested):
|
||||
* .mp3, .wav
|
||||
*
|
||||
*
|
||||
* Local audio files must reside in one of two places:
|
||||
* android_asset: file name must start with /android_asset/sound.mp3
|
||||
* sdcard: file name is just sound.mp3
|
||||
@@ -45,112 +42,111 @@ import java.util.Map.Entry;
|
||||
public class AudioHandler extends Plugin {
|
||||
|
||||
public static String TAG = "AudioHandler";
|
||||
HashMap<String,AudioPlayer> players; // Audio player object
|
||||
ArrayList<AudioPlayer> pausedForPhone; // Audio players that were paused when phone call came in
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public AudioHandler() {
|
||||
this.players = new HashMap<String,AudioPlayer>();
|
||||
this.pausedForPhone = new ArrayList<AudioPlayer>();
|
||||
}
|
||||
HashMap<String, AudioPlayer> players; // Audio player object
|
||||
ArrayList<AudioPlayer> pausedForPhone; // Audio players that were paused when phone call came in
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("startRecordingAudio")) {
|
||||
this.startRecordingAudio(args.getString(0), args.getString(1));
|
||||
}
|
||||
else if (action.equals("stopRecordingAudio")) {
|
||||
this.stopRecordingAudio(args.getString(0));
|
||||
}
|
||||
else if (action.equals("startPlayingAudio")) {
|
||||
this.startPlayingAudio(args.getString(0), args.getString(1));
|
||||
}
|
||||
else if (action.equals("seekToAudio")) {
|
||||
this.seekToAudio(args.getString(0), args.getInt(1));
|
||||
}
|
||||
else if (action.equals("pausePlayingAudio")) {
|
||||
this.pausePlayingAudio(args.getString(0));
|
||||
}
|
||||
else if (action.equals("stopPlayingAudio")) {
|
||||
this.stopPlayingAudio(args.getString(0));
|
||||
} else if (action.equals("setVolume")) {
|
||||
try {
|
||||
this.setVolume(args.getString(0), Float.parseFloat(args.getString(1)));
|
||||
} catch (NumberFormatException nfe) {
|
||||
//no-op
|
||||
}
|
||||
} else if (action.equals("getCurrentPositionAudio")) {
|
||||
float f = this.getCurrentPositionAudio(args.getString(0));
|
||||
return new PluginResult(status, f);
|
||||
}
|
||||
else if (action.equals("getDurationAudio")) {
|
||||
float f = this.getDurationAudio(args.getString(0), args.getString(1));
|
||||
return new PluginResult(status, f);
|
||||
}
|
||||
else if (action.equals("release")) {
|
||||
boolean b = this.release(args.getString(0));
|
||||
return new PluginResult(status, b);
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public AudioHandler() {
|
||||
this.players = new HashMap<String, AudioPlayer>();
|
||||
this.pausedForPhone = new ArrayList<AudioPlayer>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
if (action.equals("getCurrentPositionAudio")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("getDurationAudio")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
/**
|
||||
* Stop all audio players and recorders.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
try {
|
||||
if (action.equals("startRecordingAudio")) {
|
||||
this.startRecordingAudio(args.getString(0), args.getString(1));
|
||||
}
|
||||
else if (action.equals("stopRecordingAudio")) {
|
||||
this.stopRecordingAudio(args.getString(0));
|
||||
}
|
||||
else if (action.equals("startPlayingAudio")) {
|
||||
this.startPlayingAudio(args.getString(0), args.getString(1));
|
||||
}
|
||||
else if (action.equals("seekToAudio")) {
|
||||
this.seekToAudio(args.getString(0), args.getInt(1));
|
||||
}
|
||||
else if (action.equals("pausePlayingAudio")) {
|
||||
this.pausePlayingAudio(args.getString(0));
|
||||
}
|
||||
else if (action.equals("stopPlayingAudio")) {
|
||||
this.stopPlayingAudio(args.getString(0));
|
||||
} else if (action.equals("setVolume")) {
|
||||
try {
|
||||
this.setVolume(args.getString(0), Float.parseFloat(args.getString(1)));
|
||||
} catch (NumberFormatException nfe) {
|
||||
//no-op
|
||||
}
|
||||
} else if (action.equals("getCurrentPositionAudio")) {
|
||||
float f = this.getCurrentPositionAudio(args.getString(0));
|
||||
return new PluginResult(status, f);
|
||||
}
|
||||
else if (action.equals("getDurationAudio")) {
|
||||
float f = this.getDurationAudio(args.getString(0), args.getString(1));
|
||||
return new PluginResult(status, f);
|
||||
}
|
||||
else if (action.equals("release")) {
|
||||
boolean b = this.release(args.getString(0));
|
||||
return new PluginResult(status, b);
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
if (action.equals("getCurrentPositionAudio")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("getDurationAudio")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop all audio players and recorders.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
for (AudioPlayer audio : this.players.values()) {
|
||||
audio.destroy();
|
||||
}
|
||||
this.players.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a message is sent to plugin.
|
||||
*
|
||||
* Called when a message is sent to plugin.
|
||||
*
|
||||
* @param id The message id
|
||||
* @param data The message data
|
||||
* @return Object to stop propagation or null
|
||||
*/
|
||||
public void onMessage(String id, Object data) {
|
||||
|
||||
public Object onMessage(String id, Object data) {
|
||||
|
||||
// If phone message
|
||||
if (id.equals("telephone")) {
|
||||
|
||||
|
||||
// If phone ringing, then pause playing
|
||||
if ("ringing".equals(data) || "offhook".equals(data)) {
|
||||
|
||||
|
||||
// Get all audio players and pause them
|
||||
for (AudioPlayer audio : this.players.values()) {
|
||||
if (audio.getState() == AudioPlayer.MEDIA_RUNNING) {
|
||||
@@ -160,7 +156,7 @@ public class AudioHandler extends Plugin {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// If phone idle, then resume playing those players we paused
|
||||
else if ("idle".equals(data)) {
|
||||
for (AudioPlayer audio : this.pausedForPhone) {
|
||||
@@ -169,182 +165,175 @@ public class AudioHandler extends Plugin {
|
||||
this.pausedForPhone.clear();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Release the audio player instance to save memory.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
*/
|
||||
private boolean release(String id) {
|
||||
if (!this.players.containsKey(id)) {
|
||||
return false;
|
||||
}
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
this.players.remove(id);
|
||||
audio.destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start recording and save the specified file.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param file The name of the file
|
||||
*/
|
||||
/**
|
||||
* Release the audio player instance to save memory.
|
||||
* @param id The id of the audio player
|
||||
*/
|
||||
private boolean release(String id) {
|
||||
if (!this.players.containsKey(id)) {
|
||||
return false;
|
||||
}
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
this.players.remove(id);
|
||||
audio.destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start recording and save the specified file.
|
||||
* @param id The id of the audio player
|
||||
* @param file The name of the file
|
||||
*/
|
||||
public void startRecordingAudio(String id, String file) {
|
||||
// If already recording, then just return;
|
||||
if (this.players.containsKey(id)) {
|
||||
return;
|
||||
}
|
||||
AudioPlayer audio = new AudioPlayer(this, id);
|
||||
this.players.put(id, audio);
|
||||
audio.startRecording(file);
|
||||
// If already recording, then just return;
|
||||
if (this.players.containsKey(id)) {
|
||||
return;
|
||||
}
|
||||
AudioPlayer audio = new AudioPlayer(this, id);
|
||||
this.players.put(id, audio);
|
||||
audio.startRecording(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop recording and save to the file specified when recording started.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param id The id of the audio player
|
||||
*/
|
||||
public void stopRecordingAudio(String id) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.stopRecording();
|
||||
this.players.remove(id);
|
||||
}
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.stopRecording();
|
||||
this.players.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start or resume playing audio file.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param id The id of the audio player
|
||||
* @param file The name of the audio file.
|
||||
*/
|
||||
public void startPlayingAudio(String id, String file) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio == null) {
|
||||
audio = new AudioPlayer(this, id);
|
||||
this.players.put(id, audio);
|
||||
}
|
||||
audio.startPlaying(file);
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio == null) {
|
||||
audio = new AudioPlayer(this, id);
|
||||
this.players.put(id, audio);
|
||||
}
|
||||
audio.startPlaying(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek to a location.
|
||||
*
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param miliseconds int: number of milliseconds to skip 1000 = 1 second
|
||||
* @param id The id of the audio player
|
||||
* @param miliseconds int: number of milliseconds to skip 1000 = 1 second
|
||||
*/
|
||||
public void seekToAudio(String id, int milliseconds) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.seekToPlaying(milliseconds);
|
||||
}
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.seekToPlaying(milliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pause playing.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param id The id of the audio player
|
||||
*/
|
||||
public void pausePlayingAudio(String id) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.pausePlaying();
|
||||
}
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.pausePlaying();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop playing the audio file.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param id The id of the audio player
|
||||
*/
|
||||
public void stopPlayingAudio(String id) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.stopPlaying();
|
||||
//audio.destroy();
|
||||
//this.players.remove(id);
|
||||
}
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
audio.stopPlaying();
|
||||
//audio.destroy();
|
||||
//this.players.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get current position of playback.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param id The id of the audio player
|
||||
* @return position in msec
|
||||
*/
|
||||
public float getCurrentPositionAudio(String id) {
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
return(audio.getCurrentPosition()/1000.0f);
|
||||
}
|
||||
return -1;
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
return (audio.getCurrentPosition() / 1000.0f);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the duration of the audio file.
|
||||
*
|
||||
* @param id The id of the audio player
|
||||
* @param id The id of the audio player
|
||||
* @param file The name of the audio file.
|
||||
* @return The duration in msec.
|
||||
*/
|
||||
public float getDurationAudio(String id, String file) {
|
||||
|
||||
// Get audio file
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
return(audio.getDuration(file));
|
||||
}
|
||||
|
||||
// If not already open, then open the file
|
||||
else {
|
||||
audio = new AudioPlayer(this, id);
|
||||
this.players.put(id, audio);
|
||||
return(audio.getDuration(file));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get audio file
|
||||
AudioPlayer audio = this.players.get(id);
|
||||
if (audio != null) {
|
||||
return (audio.getDuration(file));
|
||||
}
|
||||
|
||||
// If not already open, then open the file
|
||||
else {
|
||||
audio = new AudioPlayer(this, id);
|
||||
this.players.put(id, audio);
|
||||
return (audio.getDuration(file));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the audio device to be used for playback.
|
||||
*
|
||||
*
|
||||
* @param output 1=earpiece, 2=speaker
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void setAudioOutputDevice(int output) {
|
||||
AudioManager audiMgr = (AudioManager) this.ctx.getSystemService(Context.AUDIO_SERVICE);
|
||||
if (output == 2) {
|
||||
audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_SPEAKER, AudioManager.ROUTE_ALL);
|
||||
}
|
||||
else if (output == 1) {
|
||||
audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL);
|
||||
}
|
||||
else {
|
||||
System.out.println("AudioHandler.setAudioOutputDevice() Error: Unknown output device.");
|
||||
}
|
||||
AudioManager audiMgr = (AudioManager) this.cordova.getActivity().getSystemService(Context.AUDIO_SERVICE);
|
||||
if (output == 2) {
|
||||
audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_SPEAKER, AudioManager.ROUTE_ALL);
|
||||
}
|
||||
else if (output == 1) {
|
||||
audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL);
|
||||
}
|
||||
else {
|
||||
System.out.println("AudioHandler.setAudioOutputDevice() Error: Unknown output device.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the audio device to be used for playback.
|
||||
*
|
||||
*
|
||||
* @return 1=earpiece, 2=speaker
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public int getAudioOutputDevice() {
|
||||
AudioManager audiMgr = (AudioManager) this.ctx.getSystemService(Context.AUDIO_SERVICE);
|
||||
if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_EARPIECE) {
|
||||
return 1;
|
||||
}
|
||||
else if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_SPEAKER) {
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
AudioManager audiMgr = (AudioManager) this.cordova.getActivity().getSystemService(Context.AUDIO_SERVICE);
|
||||
if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_EARPIECE) {
|
||||
return 1;
|
||||
}
|
||||
else if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_SPEAKER) {
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,432 +35,429 @@ import java.io.IOException;
|
||||
* This class implements the audio playback and recording capabilities used by Cordova.
|
||||
* It is called by the AudioHandler Cordova class.
|
||||
* Only one file can be played or recorded per class instance.
|
||||
*
|
||||
*
|
||||
* Local audio files must reside in one of two places:
|
||||
* android_asset: file name must start with /android_asset/sound.mp3
|
||||
* sdcard: file name is just sound.mp3
|
||||
* android_asset: file name must start with /android_asset/sound.mp3
|
||||
* sdcard: file name is just sound.mp3
|
||||
*/
|
||||
public class AudioPlayer implements OnCompletionListener, OnPreparedListener, OnErrorListener {
|
||||
|
||||
private static final String LOG_TAG = "AudioPlayer";
|
||||
|
||||
// AudioPlayer states
|
||||
public static int MEDIA_NONE = 0;
|
||||
public static int MEDIA_STARTING = 1;
|
||||
public static int MEDIA_RUNNING = 2;
|
||||
public static int MEDIA_PAUSED = 3;
|
||||
public static int MEDIA_STOPPED = 4;
|
||||
|
||||
// AudioPlayer message ids
|
||||
private static int MEDIA_STATE = 1;
|
||||
private static int MEDIA_DURATION = 2;
|
||||
public static int MEDIA_NONE = 0;
|
||||
public static int MEDIA_STARTING = 1;
|
||||
public static int MEDIA_RUNNING = 2;
|
||||
public static int MEDIA_PAUSED = 3;
|
||||
public static int MEDIA_STOPPED = 4;
|
||||
|
||||
// AudioPlayer message ids
|
||||
private static int MEDIA_STATE = 1;
|
||||
private static int MEDIA_DURATION = 2;
|
||||
private static int MEDIA_POSITION = 3;
|
||||
private static int MEDIA_ERROR = 9;
|
||||
|
||||
// Media error codes
|
||||
private static int MEDIA_ERROR = 9;
|
||||
|
||||
// Media error codes
|
||||
private static int MEDIA_ERR_NONE_ACTIVE = 0;
|
||||
private static int MEDIA_ERR_ABORTED = 1;
|
||||
private static int MEDIA_ERR_NETWORK = 2;
|
||||
private static int MEDIA_ERR_DECODE = 3;
|
||||
private static int MEDIA_ERR_NONE_SUPPORTED = 4;
|
||||
|
||||
private AudioHandler handler; // The AudioHandler object
|
||||
private String id; // The id of this player (used to identify Media object in JavaScript)
|
||||
private int state = MEDIA_NONE; // State of recording or playback
|
||||
private String audioFile = null; // File name to play or record to
|
||||
private float duration = -1; // Duration of audio
|
||||
|
||||
private AudioHandler handler; // The AudioHandler object
|
||||
private String id; // The id of this player (used to identify Media object in JavaScript)
|
||||
private int state = MEDIA_NONE; // State of recording or playback
|
||||
private String audioFile = null; // File name to play or record to
|
||||
private float duration = -1; // Duration of audio
|
||||
|
||||
private MediaRecorder recorder = null; // Audio recording object
|
||||
private String tempFile = null; // Temporary recording file name
|
||||
|
||||
private MediaPlayer mPlayer = null; // Audio player object
|
||||
private boolean prepareOnly = false;
|
||||
private MediaRecorder recorder = null; // Audio recording object
|
||||
private String tempFile = null; // Temporary recording file name
|
||||
|
||||
private MediaPlayer mPlayer = null; // Audio player object
|
||||
private boolean prepareOnly = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param handler The audio handler object
|
||||
* @param id The id of this audio player
|
||||
*/
|
||||
public AudioPlayer(AudioHandler handler, String id) {
|
||||
this.handler = handler;
|
||||
this.id = id;
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param handler The audio handler object
|
||||
* @param id The id of this audio player
|
||||
*/
|
||||
public AudioPlayer(AudioHandler handler, String id) {
|
||||
this.handler = handler;
|
||||
this.id = id;
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
this.tempFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmprecording.mp3";
|
||||
} else {
|
||||
this.tempFile = "/data/data/" + handler.ctx.getPackageName() + "/cache/tmprecording.mp3";
|
||||
this.tempFile = "/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/tmprecording.mp3";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy player and stop audio playing or recording.
|
||||
*/
|
||||
public void destroy() {
|
||||
|
||||
// Stop any play or record
|
||||
if (this.mPlayer != null) {
|
||||
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
|
||||
this.mPlayer.stop();
|
||||
this.setState(MEDIA_STOPPED);
|
||||
}
|
||||
this.mPlayer.release();
|
||||
this.mPlayer = null;
|
||||
}
|
||||
if (this.recorder != null) {
|
||||
this.stopRecording();
|
||||
this.recorder.release();
|
||||
this.recorder = null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Destroy player and stop audio playing or recording.
|
||||
*/
|
||||
public void destroy() {
|
||||
// Stop any play or record
|
||||
if (this.mPlayer != null) {
|
||||
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
|
||||
this.mPlayer.stop();
|
||||
this.setState(MEDIA_STOPPED);
|
||||
}
|
||||
this.mPlayer.release();
|
||||
this.mPlayer = null;
|
||||
}
|
||||
if (this.recorder != null) {
|
||||
this.stopRecording();
|
||||
this.recorder.release();
|
||||
this.recorder = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start recording the specified file.
|
||||
*
|
||||
* @param file The name of the file
|
||||
*/
|
||||
public void startRecording(String file) {
|
||||
if (this.mPlayer != null) {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: Can't record in play mode.");
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||
}
|
||||
|
||||
// Make sure we're not already recording
|
||||
else if (this.recorder == null) {
|
||||
this.audioFile = file;
|
||||
this.recorder = new MediaRecorder();
|
||||
this.recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
|
||||
this.recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); // THREE_GPP);
|
||||
this.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //AMR_NB);
|
||||
this.recorder.setOutputFile(this.tempFile);
|
||||
try {
|
||||
this.recorder.prepare();
|
||||
this.recorder.start();
|
||||
this.setState(MEDIA_RUNNING);
|
||||
return;
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: Already recording.");
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save temporary recorded file to specified name
|
||||
*
|
||||
* @param file
|
||||
*/
|
||||
public void moveFile(String file) {
|
||||
/* this is a hack to save the file as the specified name */
|
||||
File f = new File(this.tempFile);
|
||||
/**
|
||||
* Start recording the specified file.
|
||||
*
|
||||
* @param file The name of the file
|
||||
*/
|
||||
public void startRecording(String file) {
|
||||
if (this.mPlayer != null) {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: Can't record in play mode.");
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||
}
|
||||
// Make sure we're not already recording
|
||||
else if (this.recorder == null) {
|
||||
this.audioFile = file;
|
||||
this.recorder = new MediaRecorder();
|
||||
this.recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
|
||||
this.recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); // THREE_GPP);
|
||||
this.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //AMR_NB);
|
||||
this.recorder.setOutputFile(this.tempFile);
|
||||
try {
|
||||
this.recorder.prepare();
|
||||
this.recorder.start();
|
||||
this.setState(MEDIA_RUNNING);
|
||||
return;
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: Already recording.");
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save temporary recorded file to specified name
|
||||
*
|
||||
* @param file
|
||||
*/
|
||||
public void moveFile(String file) {
|
||||
/* this is a hack to save the file as the specified name */
|
||||
File f = new File(this.tempFile);
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
f.renameTo(new File(Environment.getExternalStorageDirectory().getAbsolutePath()
|
||||
f.renameTo(new File(Environment.getExternalStorageDirectory().getAbsolutePath()
|
||||
+ File.separator + file));
|
||||
} else {
|
||||
f.renameTo(new File("/data/data/" + handler.ctx.getPackageName() + "/cache/" + file));
|
||||
f.renameTo(new File("/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/" + file));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop recording and save to the file specified when recording started.
|
||||
*/
|
||||
public void stopRecording() {
|
||||
if (this.recorder != null) {
|
||||
try{
|
||||
if (this.state == MEDIA_RUNNING) {
|
||||
this.recorder.stop();
|
||||
this.setState(MEDIA_STOPPED);
|
||||
}
|
||||
this.moveFile(this.audioFile);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stopRecording() {
|
||||
if (this.recorder != null) {
|
||||
try{
|
||||
if (this.state == MEDIA_RUNNING) {
|
||||
this.recorder.stop();
|
||||
this.setState(MEDIA_STOPPED);
|
||||
}
|
||||
this.moveFile(this.audioFile);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start or resume playing audio file.
|
||||
*
|
||||
* @param file The name of the audio file.
|
||||
* @param file The name of the audio file.
|
||||
*/
|
||||
public void startPlaying(String file) {
|
||||
if (this.recorder != null) {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode.");
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||
}
|
||||
|
||||
// If this is a new request to play audio, or stopped
|
||||
else if ((this.mPlayer == null) || (this.state == MEDIA_STOPPED)) {
|
||||
try {
|
||||
// If stopped, then reset player
|
||||
if (this.mPlayer != null) {
|
||||
this.mPlayer.reset();
|
||||
}
|
||||
// Otherwise, create a new one
|
||||
else {
|
||||
this.mPlayer = new MediaPlayer();
|
||||
}
|
||||
this.audioFile = file;
|
||||
|
||||
// If streaming file
|
||||
if (this.isStreaming(file)) {
|
||||
this.mPlayer.setDataSource(file);
|
||||
this.mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||
this.setState(MEDIA_STARTING);
|
||||
this.mPlayer.setOnPreparedListener(this);
|
||||
this.mPlayer.prepareAsync();
|
||||
}
|
||||
|
||||
// If local file
|
||||
else {
|
||||
if (file.startsWith("/android_asset/")) {
|
||||
String f = file.substring(15);
|
||||
android.content.res.AssetFileDescriptor fd = this.handler.ctx.getBaseContext().getAssets().openFd(f);
|
||||
this.mPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
|
||||
}
|
||||
public void startPlaying(String file) {
|
||||
if (this.recorder != null) {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode.");
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
|
||||
}
|
||||
|
||||
// If this is a new request to play audio, or stopped
|
||||
else if ((this.mPlayer == null) || (this.state == MEDIA_STOPPED)) {
|
||||
try {
|
||||
// If stopped, then reset player
|
||||
if (this.mPlayer != null) {
|
||||
this.mPlayer.reset();
|
||||
}
|
||||
// Otherwise, create a new one
|
||||
else {
|
||||
this.mPlayer = new MediaPlayer();
|
||||
}
|
||||
this.audioFile = file;
|
||||
|
||||
// If streaming file
|
||||
if (this.isStreaming(file)) {
|
||||
this.mPlayer.setDataSource(file);
|
||||
this.mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||
this.setState(MEDIA_STARTING);
|
||||
this.mPlayer.setOnPreparedListener(this);
|
||||
this.mPlayer.prepareAsync();
|
||||
}
|
||||
|
||||
// If local file
|
||||
else {
|
||||
if (file.startsWith("/android_asset/")) {
|
||||
String f = file.substring(15);
|
||||
android.content.res.AssetFileDescriptor fd = this.handler.cordova.getActivity().getAssets().openFd(f);
|
||||
this.mPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
|
||||
}
|
||||
else {
|
||||
File fp = new File(file);
|
||||
if (fp.exists()) {
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
this.mPlayer.setDataSource(fileInputStream.getFD());
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.mPlayer.setDataSource("/sdcard/" + file);
|
||||
}
|
||||
}
|
||||
this.setState(MEDIA_STARTING);
|
||||
this.mPlayer.setOnPreparedListener(this);
|
||||
this.mPlayer.prepare();
|
||||
this.setState(MEDIA_STARTING);
|
||||
this.mPlayer.setOnPreparedListener(this);
|
||||
this.mPlayer.prepare();
|
||||
|
||||
// Get duration
|
||||
this.duration = getDurationInSeconds();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||
}
|
||||
}
|
||||
// Get duration
|
||||
this.duration = getDurationInSeconds();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
|
||||
}
|
||||
}
|
||||
|
||||
// If we have already have created an audio player
|
||||
else {
|
||||
|
||||
// If player has been paused, then resume playback
|
||||
if ((this.state == MEDIA_PAUSED) || (this.state == MEDIA_STARTING)) {
|
||||
this.mPlayer.start();
|
||||
this.setState(MEDIA_RUNNING);
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: startPlaying() called during invalid state: "+this.state);
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we have already have created an audio player
|
||||
else {
|
||||
|
||||
/**
|
||||
* Seek or jump to a new time in the track.
|
||||
*/
|
||||
public void seekToPlaying(int milliseconds) {
|
||||
if (this.mPlayer != null) {
|
||||
this.mPlayer.seekTo(milliseconds);
|
||||
Log.d(LOG_TAG, "Send a onStatus update for the new seek");
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_POSITION+", "+milliseconds/1000.0f+");");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause playing.
|
||||
*/
|
||||
public void pausePlaying() {
|
||||
|
||||
// If playing, then pause
|
||||
if (this.state == MEDIA_RUNNING) {
|
||||
this.mPlayer.pause();
|
||||
this.setState(MEDIA_PAUSED);
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: "+this.state);
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_NONE_ACTIVE+"});");
|
||||
}
|
||||
}
|
||||
// If player has been paused, then resume playback
|
||||
if ((this.state == MEDIA_PAUSED) || (this.state == MEDIA_STARTING)) {
|
||||
this.mPlayer.start();
|
||||
this.setState(MEDIA_RUNNING);
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: startPlaying() called during invalid state: " + this.state);
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek or jump to a new time in the track.
|
||||
*/
|
||||
public void seekToPlaying(int milliseconds) {
|
||||
if (this.mPlayer != null) {
|
||||
this.mPlayer.seekTo(milliseconds);
|
||||
Log.d(LOG_TAG, "Send a onStatus update for the new seek");
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + milliseconds / 1000.0f + ");");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause playing.
|
||||
*/
|
||||
public void pausePlaying() {
|
||||
|
||||
// If playing, then pause
|
||||
if (this.state == MEDIA_RUNNING) {
|
||||
this.mPlayer.pause();
|
||||
this.setState(MEDIA_PAUSED);
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: " + this.state);
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop playing the audio file.
|
||||
*/
|
||||
public void stopPlaying() {
|
||||
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
|
||||
this.mPlayer.stop();
|
||||
this.setState(MEDIA_STOPPED);
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: "+this.state);
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_NONE_ACTIVE+"});");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to be invoked when playback of a media source has completed.
|
||||
*
|
||||
* @param mPlayer The MediaPlayer that reached the end of the file
|
||||
*/
|
||||
public void onCompletion(MediaPlayer mPlayer) {
|
||||
this.setState(MEDIA_STOPPED);
|
||||
}
|
||||
|
||||
public void stopPlaying() {
|
||||
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
|
||||
this.mPlayer.stop();
|
||||
this.setState(MEDIA_STOPPED);
|
||||
}
|
||||
else {
|
||||
Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: " + this.state);
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to be invoked when playback of a media source has completed.
|
||||
*
|
||||
* @param mPlayer The MediaPlayer that reached the end of the file
|
||||
*/
|
||||
public void onCompletion(MediaPlayer mPlayer) {
|
||||
this.setState(MEDIA_STOPPED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current position of playback.
|
||||
*
|
||||
* @return position in msec or -1 if not playing
|
||||
* @return position in msec or -1 if not playing
|
||||
*/
|
||||
public long getCurrentPosition() {
|
||||
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
|
||||
int curPos = this.mPlayer.getCurrentPosition();
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_POSITION+", "+curPos/1000.0f+");");
|
||||
return curPos;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if playback file is streaming or local.
|
||||
* It is streaming if file name starts with "http://"
|
||||
*
|
||||
* @param file The file name
|
||||
* @return T=streaming, F=local
|
||||
*/
|
||||
public boolean isStreaming(String file) {
|
||||
if (file.contains("http://") || file.contains("https://")) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the duration of the audio file.
|
||||
public long getCurrentPosition() {
|
||||
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
|
||||
int curPos = this.mPlayer.getCurrentPosition();
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + curPos / 1000.0f + ");");
|
||||
return curPos;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if playback file is streaming or local.
|
||||
* It is streaming if file name starts with "http://"
|
||||
*
|
||||
* @param file The name of the audio file.
|
||||
* @return The duration in msec.
|
||||
* -1=can't be determined
|
||||
* -2=not allowed
|
||||
* @param file The file name
|
||||
* @return T=streaming, F=local
|
||||
*/
|
||||
public float getDuration(String file) {
|
||||
|
||||
// Can't get duration of recording
|
||||
if (this.recorder != null) {
|
||||
return(-2); // not allowed
|
||||
}
|
||||
|
||||
// If audio file already loaded and started, then return duration
|
||||
if (this.mPlayer != null) {
|
||||
return this.duration;
|
||||
}
|
||||
|
||||
// If no player yet, then create one
|
||||
else {
|
||||
this.prepareOnly = true;
|
||||
this.startPlaying(file);
|
||||
|
||||
// This will only return value for local, since streaming
|
||||
// file hasn't been read yet.
|
||||
return this.duration;
|
||||
}
|
||||
}
|
||||
public boolean isStreaming(String file) {
|
||||
if (file.contains("http://") || file.contains("https://")) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the media source is ready for playback.
|
||||
*
|
||||
* @param mPlayer The MediaPlayer that is ready for playback
|
||||
*/
|
||||
public void onPrepared(MediaPlayer mPlayer) {
|
||||
// Listen for playback completion
|
||||
this.mPlayer.setOnCompletionListener(this);
|
||||
/**
|
||||
* Get the duration of the audio file.
|
||||
*
|
||||
* @param file The name of the audio file.
|
||||
* @return The duration in msec.
|
||||
* -1=can't be determined
|
||||
* -2=not allowed
|
||||
*/
|
||||
public float getDuration(String file) {
|
||||
|
||||
// If start playing after prepared
|
||||
if (!this.prepareOnly) {
|
||||
|
||||
// Start playing
|
||||
this.mPlayer.start();
|
||||
// Can't get duration of recording
|
||||
if (this.recorder != null) {
|
||||
return (-2); // not allowed
|
||||
}
|
||||
|
||||
// Set player init flag
|
||||
this.setState(MEDIA_RUNNING);
|
||||
}
|
||||
|
||||
// Save off duration
|
||||
this.duration = getDurationInSeconds();
|
||||
this.prepareOnly = false;
|
||||
// If audio file already loaded and started, then return duration
|
||||
if (this.mPlayer != null) {
|
||||
return this.duration;
|
||||
}
|
||||
|
||||
// Send status notification to JavaScript
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_DURATION+","+this.duration+");");
|
||||
|
||||
}
|
||||
// If no player yet, then create one
|
||||
else {
|
||||
this.prepareOnly = true;
|
||||
this.startPlaying(file);
|
||||
|
||||
/**
|
||||
* By default Android returns the length of audio in mills but we want seconds
|
||||
*
|
||||
* @return length of clip in seconds
|
||||
*/
|
||||
private float getDurationInSeconds() {
|
||||
return (this.mPlayer.getDuration() / 1000.0f);
|
||||
}
|
||||
// This will only return value for local, since streaming
|
||||
// file hasn't been read yet.
|
||||
return this.duration;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to be invoked when there has been an error during an asynchronous operation
|
||||
* (other errors will throw exceptions at method call time).
|
||||
*
|
||||
* @param mPlayer the MediaPlayer the error pertains to
|
||||
* @param arg1 the type of error that has occurred: (MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_SERVER_DIED)
|
||||
* @param arg2 an extra code, specific to the error.
|
||||
*/
|
||||
public boolean onError(MediaPlayer mPlayer, int arg1, int arg2) {
|
||||
Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2+")");
|
||||
/**
|
||||
* Callback to be invoked when the media source is ready for playback.
|
||||
*
|
||||
* @param mPlayer The MediaPlayer that is ready for playback
|
||||
*/
|
||||
public void onPrepared(MediaPlayer mPlayer) {
|
||||
// Listen for playback completion
|
||||
this.mPlayer.setOnCompletionListener(this);
|
||||
|
||||
// TODO: Not sure if this needs to be sent?
|
||||
this.mPlayer.stop();
|
||||
this.mPlayer.release();
|
||||
|
||||
// Send error notification to JavaScript
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', { \"code\":"+arg1+"});");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state and send it to JavaScript.
|
||||
*
|
||||
* @param state
|
||||
*/
|
||||
private void setState(int state) {
|
||||
if (this.state != state) {
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_STATE+", "+state+");");
|
||||
}
|
||||
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the audio state.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public int getState() {
|
||||
return this.state;
|
||||
}
|
||||
// If start playing after prepared
|
||||
if (!this.prepareOnly) {
|
||||
|
||||
/**
|
||||
* Set the volume for audio player
|
||||
*
|
||||
* @param volume
|
||||
*/
|
||||
// Start playing
|
||||
this.mPlayer.start();
|
||||
|
||||
// Set player init flag
|
||||
this.setState(MEDIA_RUNNING);
|
||||
}
|
||||
|
||||
// Save off duration
|
||||
this.duration = getDurationInSeconds();
|
||||
this.prepareOnly = false;
|
||||
|
||||
// Send status notification to JavaScript
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_DURATION + "," + this.duration + ");");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* By default Android returns the length of audio in mills but we want seconds
|
||||
*
|
||||
* @return length of clip in seconds
|
||||
*/
|
||||
private float getDurationInSeconds() {
|
||||
return (this.mPlayer.getDuration() / 1000.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to be invoked when there has been an error during an asynchronous operation
|
||||
* (other errors will throw exceptions at method call time).
|
||||
*
|
||||
* @param mPlayer the MediaPlayer the error pertains to
|
||||
* @param arg1 the type of error that has occurred: (MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_SERVER_DIED)
|
||||
* @param arg2 an extra code, specific to the error.
|
||||
*/
|
||||
public boolean onError(MediaPlayer mPlayer, int arg1, int arg2) {
|
||||
Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2 + ")");
|
||||
|
||||
// TODO: Not sure if this needs to be sent?
|
||||
this.mPlayer.stop();
|
||||
this.mPlayer.release();
|
||||
|
||||
// Send error notification to JavaScript
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', { \"code\":" + arg1 + "});");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state and send it to JavaScript.
|
||||
*
|
||||
* @param state
|
||||
*/
|
||||
private void setState(int state) {
|
||||
if (this.state != state) {
|
||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_STATE + ", " + state + ");");
|
||||
}
|
||||
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the audio state.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public int getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the volume for audio player
|
||||
*
|
||||
* @param volume
|
||||
*/
|
||||
public void setVolume(float volume) {
|
||||
this.mPlayer.setVolume(volume, volume);
|
||||
}
|
||||
|
||||
@@ -24,46 +24,46 @@ package org.apache.cordova;
|
||||
public class AuthenticationToken {
|
||||
private String userName;
|
||||
private String password;
|
||||
|
||||
|
||||
/**
|
||||
* Gets the user name.
|
||||
*
|
||||
*
|
||||
* @return the user name
|
||||
*/
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the user name.
|
||||
*
|
||||
*
|
||||
* @param userName
|
||||
* the new user name
|
||||
*/
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the password.
|
||||
*
|
||||
*
|
||||
* @return the password
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the password.
|
||||
*
|
||||
*
|
||||
* @param password
|
||||
* the new password
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -32,23 +31,23 @@ import android.content.IntentFilter;
|
||||
import android.util.Log;
|
||||
|
||||
public class BatteryListener extends Plugin {
|
||||
|
||||
|
||||
private static final String LOG_TAG = "BatteryManager";
|
||||
|
||||
BroadcastReceiver receiver;
|
||||
|
||||
private String batteryCallbackId = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public BatteryListener() {
|
||||
this.receiver = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
@@ -56,43 +55,43 @@ public class BatteryListener extends Plugin {
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.INVALID_ACTION;
|
||||
String result = "Unsupported Operation: " + action;
|
||||
|
||||
String result = "Unsupported Operation: " + action;
|
||||
|
||||
if (action.equals("start")) {
|
||||
if (this.batteryCallbackId != null) {
|
||||
return new PluginResult(PluginResult.Status.ERROR, "Battery listener already running.");
|
||||
}
|
||||
if (this.batteryCallbackId != null) {
|
||||
return new PluginResult(PluginResult.Status.ERROR, "Battery listener already running.");
|
||||
}
|
||||
this.batteryCallbackId = callbackId;
|
||||
|
||||
// We need to listen to power events to update battery status
|
||||
IntentFilter intentFilter = new IntentFilter() ;
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||
if (this.receiver == null) {
|
||||
this.receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
updateBatteryInfo(intent);
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
updateBatteryInfo(intent);
|
||||
}
|
||||
};
|
||||
ctx.registerReceiver(this.receiver, intentFilter);
|
||||
cordova.getActivity().registerReceiver(this.receiver, intentFilter);
|
||||
}
|
||||
|
||||
// Don't return any result now, since status results will be sent when events come in from broadcast receiver
|
||||
// Don't return any result now, since status results will be sent when events come in from broadcast receiver
|
||||
PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
pluginResult.setKeepCallback(true);
|
||||
return pluginResult;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else if (action.equals("stop")) {
|
||||
removeBatteryListener();
|
||||
this.sendUpdate(new JSONObject(), false); // release status callback in JS side
|
||||
this.batteryCallbackId = null;
|
||||
return new PluginResult(PluginResult.Status.OK);
|
||||
}
|
||||
|
||||
|
||||
return new PluginResult(status, result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop battery receiver.
|
||||
*/
|
||||
@@ -106,7 +105,7 @@ public class BatteryListener extends Plugin {
|
||||
private void removeBatteryListener() {
|
||||
if (this.receiver != null) {
|
||||
try {
|
||||
this.ctx.unregisterReceiver(this.receiver);
|
||||
this.cordova.getActivity().unregisterReceiver(this.receiver);
|
||||
this.receiver = null;
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error unregistering battery receiver: " + e.getMessage(), e);
|
||||
@@ -116,7 +115,7 @@ public class BatteryListener extends Plugin {
|
||||
|
||||
/**
|
||||
* Creates a JSONObject with the current battery information
|
||||
*
|
||||
*
|
||||
* @param batteryIntent the current battery information
|
||||
* @return a JSONObject containing the battery status information
|
||||
*/
|
||||
@@ -133,24 +132,24 @@ public class BatteryListener extends Plugin {
|
||||
|
||||
/**
|
||||
* Updates the JavaScript side whenever the battery changes
|
||||
*
|
||||
*
|
||||
* @param batteryIntent the current battery information
|
||||
* @return
|
||||
*/
|
||||
private void updateBatteryInfo(Intent batteryIntent) {
|
||||
private void updateBatteryInfo(Intent batteryIntent) {
|
||||
sendUpdate(this.getBatteryInfo(batteryIntent), true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new plugin result and send it back to JavaScript
|
||||
*
|
||||
*
|
||||
* @param connection the network info to set as navigator.connection
|
||||
*/
|
||||
private void sendUpdate(JSONObject info, boolean keepCallback) {
|
||||
if (this.batteryCallbackId != null) {
|
||||
PluginResult result = new PluginResult(PluginResult.Status.OK, info);
|
||||
result.setKeepCallback(keepCallback);
|
||||
this.success(result, this.batteryCallbackId);
|
||||
}
|
||||
if (this.batteryCallbackId != null) {
|
||||
PluginResult result = new PluginResult(PluginResult.Status.OK, info);
|
||||
result.setKeepCallback(keepCallback);
|
||||
this.success(result, this.batteryCallbackId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,337 +25,332 @@ import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* This class provides a way for Java to run JavaScript in the web page that has loaded Cordova.
|
||||
* The CallbackServer class implements an XHR server and a polling server with a list of JavaScript
|
||||
* statements that are to be executed on the web page.
|
||||
*
|
||||
*
|
||||
* The process flow for XHR is:
|
||||
* 1. JavaScript makes an async XHR call.
|
||||
* 2. The server holds the connection open until data is available.
|
||||
* 3. The server writes the data to the client and closes the connection.
|
||||
* 4. The server immediately starts listening for the next XHR call.
|
||||
* 1. JavaScript makes an async XHR call.
|
||||
* 2. The server holds the connection open until data is available.
|
||||
* 3. The server writes the data to the client and closes the connection.
|
||||
* 4. The server immediately starts listening for the next XHR call.
|
||||
* 5. The client receives this XHR response, processes it.
|
||||
* 6. The client sends a new async XHR request.
|
||||
*
|
||||
* The CallbackServer class requires the following permission in Android manifest file
|
||||
* <uses-permission android:name="android.permission.INTERNET" />
|
||||
*
|
||||
*
|
||||
* If the device has a proxy set, then XHR cannot be used, so polling must be used instead.
|
||||
* This can be determined by the client by calling CallbackServer.usePolling().
|
||||
*
|
||||
* This can be determined by the client by calling CallbackServer.usePolling().
|
||||
*
|
||||
* The process flow for polling is:
|
||||
* 1. The client calls CallbackServer.getJavascript() to retrieve next statement.
|
||||
* 2. If statement available, then client processes it.
|
||||
* 3. The client repeats #1 in loop.
|
||||
* 3. The client repeats #1 in loop.
|
||||
*/
|
||||
public class CallbackServer implements Runnable {
|
||||
|
||||
private static final String LOG_TAG = "CallbackServer";
|
||||
|
||||
/**
|
||||
* The list of JavaScript statements to be sent to JavaScript.
|
||||
*/
|
||||
private LinkedList<String> javascript;
|
||||
|
||||
/**
|
||||
* The port to listen on.
|
||||
*/
|
||||
private int port;
|
||||
|
||||
/**
|
||||
* The server thread.
|
||||
*/
|
||||
private Thread serverThread;
|
||||
|
||||
/**
|
||||
* Indicates the server is running.
|
||||
*/
|
||||
private boolean active;
|
||||
|
||||
/**
|
||||
* Indicates that the JavaScript statements list is empty
|
||||
*/
|
||||
private boolean empty;
|
||||
|
||||
/**
|
||||
* Indicates that polling should be used instead of XHR.
|
||||
*/
|
||||
private boolean usePolling = true;
|
||||
|
||||
/**
|
||||
* Security token to prevent other apps from accessing this callback server via XHR
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CallbackServer() {
|
||||
//System.out.println("CallbackServer()");
|
||||
this.active = false;
|
||||
this.empty = true;
|
||||
this.port = 0;
|
||||
this.javascript = new LinkedList<String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Init callback server and start XHR if running local app.
|
||||
*
|
||||
* If Cordova app is loaded from file://, then we can use XHR
|
||||
* otherwise we have to use polling due to cross-domain security restrictions.
|
||||
*
|
||||
* @param url The URL of the Cordova app being loaded
|
||||
*/
|
||||
public void init(String url) {
|
||||
//System.out.println("CallbackServer.start("+url+")");
|
||||
this.active = false;
|
||||
this.empty = true;
|
||||
this.port = 0;
|
||||
this.javascript = new LinkedList<String>();
|
||||
@SuppressWarnings("unused")
|
||||
private static final String LOG_TAG = "CallbackServer";
|
||||
|
||||
/**
|
||||
* The list of JavaScript statements to be sent to JavaScript.
|
||||
*/
|
||||
private LinkedList<String> javascript;
|
||||
|
||||
/**
|
||||
* The port to listen on.
|
||||
*/
|
||||
private int port;
|
||||
|
||||
/**
|
||||
* The server thread.
|
||||
*/
|
||||
private Thread serverThread;
|
||||
|
||||
/**
|
||||
* Indicates the server is running.
|
||||
*/
|
||||
private boolean active;
|
||||
|
||||
/**
|
||||
* Indicates that the JavaScript statements list is empty
|
||||
*/
|
||||
private boolean empty;
|
||||
|
||||
/**
|
||||
* Indicates that polling should be used instead of XHR.
|
||||
*/
|
||||
private boolean usePolling = true;
|
||||
|
||||
/**
|
||||
* Security token to prevent other apps from accessing this callback server via XHR
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CallbackServer() {
|
||||
//Log.d(LOG_TAG, "CallbackServer()");
|
||||
this.active = false;
|
||||
this.empty = true;
|
||||
this.port = 0;
|
||||
this.javascript = new LinkedList<String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Init callback server and start XHR if running local app.
|
||||
*
|
||||
* If Cordova app is loaded from file://, then we can use XHR
|
||||
* otherwise we have to use polling due to cross-domain security restrictions.
|
||||
*
|
||||
* @param url The URL of the Cordova app being loaded
|
||||
*/
|
||||
public void init(String url) {
|
||||
//System.out.println("CallbackServer.start("+url+")");
|
||||
this.active = false;
|
||||
this.empty = true;
|
||||
this.port = 0;
|
||||
this.javascript = new LinkedList<String>();
|
||||
|
||||
// Determine if XHR or polling is to be used
|
||||
if ((url != null) && !url.startsWith("file://")) {
|
||||
this.usePolling = true;
|
||||
this.stopServer();
|
||||
}
|
||||
else if (android.net.Proxy.getDefaultHost() != null) {
|
||||
this.usePolling = true;
|
||||
this.stopServer();
|
||||
}
|
||||
else {
|
||||
this.usePolling = false;
|
||||
this.startServer();
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if XHR or polling is to be used
|
||||
if ((url != null) && !url.startsWith("file://")) {
|
||||
this.usePolling = true;
|
||||
this.stopServer();
|
||||
}
|
||||
else if (android.net.Proxy.getDefaultHost() != null) {
|
||||
this.usePolling = true;
|
||||
this.stopServer();
|
||||
}
|
||||
else {
|
||||
this.usePolling = false;
|
||||
this.startServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-init when loading a new HTML page into webview.
|
||||
*
|
||||
*
|
||||
* @param url The URL of the Cordova app being loaded
|
||||
*/
|
||||
public void reinit(String url) {
|
||||
this.stopServer();
|
||||
this.init(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if polling is being used instead of XHR.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean usePolling() {
|
||||
return this.usePolling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the port that this server is running on.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the security token that this server requires when calling getJavascript().
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getToken() {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the server on a new thread.
|
||||
*/
|
||||
public void startServer() {
|
||||
//System.out.println("CallbackServer.startServer()");
|
||||
this.active = false;
|
||||
|
||||
// Start server on new thread
|
||||
this.serverThread = new Thread(this);
|
||||
this.serverThread.start();
|
||||
}
|
||||
public void reinit(String url) {
|
||||
this.stopServer();
|
||||
this.init(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart the server on a new thread.
|
||||
*/
|
||||
public void restartServer() {
|
||||
|
||||
// Stop server
|
||||
this.stopServer();
|
||||
|
||||
// Start server again
|
||||
this.startServer();
|
||||
}
|
||||
/**
|
||||
* Return if polling is being used instead of XHR.
|
||||
* @return
|
||||
*/
|
||||
public boolean usePolling() {
|
||||
return this.usePolling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start running the server.
|
||||
* This is called automatically when the server thread is started.
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
// Start server
|
||||
try {
|
||||
this.active = true;
|
||||
String request;
|
||||
ServerSocket waitSocket = new ServerSocket(0);
|
||||
this.port = waitSocket.getLocalPort();
|
||||
//System.out.println("CallbackServer -- using port " +this.port);
|
||||
this.token = java.util.UUID.randomUUID().toString();
|
||||
//System.out.println("CallbackServer -- using token "+this.token);
|
||||
/**
|
||||
* Get the port that this server is running on.
|
||||
* @return
|
||||
*/
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
while (this.active) {
|
||||
//System.out.println("CallbackServer: Waiting for data on socket");
|
||||
Socket connection = waitSocket.accept();
|
||||
BufferedReader xhrReader = new BufferedReader(new InputStreamReader(connection.getInputStream()),40);
|
||||
DataOutputStream output = new DataOutputStream(connection.getOutputStream());
|
||||
request = xhrReader.readLine();
|
||||
String response = "";
|
||||
//System.out.println("CallbackServerRequest="+request);
|
||||
if (this.active && (request != null)) {
|
||||
if (request.contains("GET")) {
|
||||
|
||||
// Get requested file
|
||||
String[] requestParts = request.split(" ");
|
||||
|
||||
// Must have security token
|
||||
if ((requestParts.length == 3) && (requestParts[1].substring(1).equals(this.token))) {
|
||||
//System.out.println("CallbackServer -- Processing GET request");
|
||||
/**
|
||||
* Get the security token that this server requires when calling getJavascript().
|
||||
* @return
|
||||
*/
|
||||
public String getToken() {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
// Wait until there is some data to send, or send empty data every 10 sec
|
||||
// to prevent XHR timeout on the client
|
||||
synchronized (this) {
|
||||
while (this.empty) {
|
||||
try {
|
||||
this.wait(10000); // prevent timeout from happening
|
||||
//System.out.println("CallbackServer>>> break <<<");
|
||||
break;
|
||||
}
|
||||
catch (Exception e) { }
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Start the server on a new thread.
|
||||
*/
|
||||
public void startServer() {
|
||||
//Log.d(LOG_TAG, "CallbackServer.startServer()");
|
||||
this.active = false;
|
||||
|
||||
// If server is still running
|
||||
if (this.active) {
|
||||
// Start server on new thread
|
||||
this.serverThread = new Thread(this);
|
||||
this.serverThread.start();
|
||||
}
|
||||
|
||||
// If no data, then send 404 back to client before it times out
|
||||
if (this.empty) {
|
||||
//System.out.println("CallbackServer -- sending data 0");
|
||||
response = "HTTP/1.1 404 NO DATA\r\n\r\n "; // need to send content otherwise some Android devices fail, so send space
|
||||
}
|
||||
else {
|
||||
//System.out.println("CallbackServer -- sending item");
|
||||
response = "HTTP/1.1 200 OK\r\n\r\n";
|
||||
String js = this.getJavascript();
|
||||
if (js != null) {
|
||||
response += encode(js, "UTF-8");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
response = "HTTP/1.1 503 Service Unavailable\r\n\r\n ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
response = "HTTP/1.1 403 Forbidden\r\n\r\n ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
response = "HTTP/1.1 400 Bad Request\r\n\r\n ";
|
||||
}
|
||||
//System.out.println("CallbackServer: response="+response);
|
||||
//System.out.println("CallbackServer: closing output");
|
||||
output.writeBytes(response);
|
||||
output.flush();
|
||||
}
|
||||
output.close();
|
||||
xhrReader.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.active = false;
|
||||
//System.out.println("CallbackServer.startServer() - EXIT");
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop server.
|
||||
* This stops the thread that the server is running on.
|
||||
*/
|
||||
public void stopServer() {
|
||||
//System.out.println("CallbackServer.stopServer()");
|
||||
if (this.active) {
|
||||
this.active = false;
|
||||
/**
|
||||
* Restart the server on a new thread.
|
||||
*/
|
||||
public void restartServer() {
|
||||
|
||||
// Break out of server wait
|
||||
synchronized (this) {
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Stop server
|
||||
this.stopServer();
|
||||
|
||||
// Start server again
|
||||
this.startServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start running the server.
|
||||
* This is called automatically when the server thread is started.
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
// Start server
|
||||
try {
|
||||
this.active = true;
|
||||
String request;
|
||||
ServerSocket waitSocket = new ServerSocket(0);
|
||||
this.port = waitSocket.getLocalPort();
|
||||
//Log.d(LOG_TAG, "CallbackServer -- using port " +this.port);
|
||||
this.token = java.util.UUID.randomUUID().toString();
|
||||
//Log.d(LOG_TAG, "CallbackServer -- using token "+this.token);
|
||||
|
||||
while (this.active) {
|
||||
//Log.d(LOG_TAG, "CallbackServer: Waiting for data on socket");
|
||||
Socket connection = waitSocket.accept();
|
||||
BufferedReader xhrReader = new BufferedReader(new InputStreamReader(connection.getInputStream()), 40);
|
||||
DataOutputStream output = new DataOutputStream(connection.getOutputStream());
|
||||
request = xhrReader.readLine();
|
||||
String response = "";
|
||||
//Log.d(LOG_TAG, "CallbackServerRequest="+request);
|
||||
if (this.active && (request != null)) {
|
||||
if (request.contains("GET")) {
|
||||
|
||||
// Get requested file
|
||||
String[] requestParts = request.split(" ");
|
||||
|
||||
// Must have security token
|
||||
if ((requestParts.length == 3) && (requestParts[1].substring(1).equals(this.token))) {
|
||||
//Log.d(LOG_TAG, "CallbackServer -- Processing GET request");
|
||||
|
||||
// Wait until there is some data to send, or send empty data every 10 sec
|
||||
// to prevent XHR timeout on the client
|
||||
synchronized (this) {
|
||||
while (this.empty) {
|
||||
try {
|
||||
this.wait(10000); // prevent timeout from happening
|
||||
//Log.d(LOG_TAG, "CallbackServer>>> break <<<");
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If server is still running
|
||||
if (this.active) {
|
||||
|
||||
// If no data, then send 404 back to client before it times out
|
||||
if (this.empty) {
|
||||
//Log.d(LOG_TAG, "CallbackServer -- sending data 0");
|
||||
response = "HTTP/1.1 404 NO DATA\r\n\r\n "; // need to send content otherwise some Android devices fail, so send space
|
||||
}
|
||||
else {
|
||||
//Log.d(LOG_TAG, "CallbackServer -- sending item");
|
||||
response = "HTTP/1.1 200 OK\r\n\r\n";
|
||||
String js = this.getJavascript();
|
||||
if (js != null) {
|
||||
response += encode(js, "UTF-8");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
response = "HTTP/1.1 503 Service Unavailable\r\n\r\n ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
response = "HTTP/1.1 403 Forbidden\r\n\r\n ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
response = "HTTP/1.1 400 Bad Request\r\n\r\n ";
|
||||
}
|
||||
//Log.d(LOG_TAG, "CallbackServer: response="+response);
|
||||
//Log.d(LOG_TAG, "CallbackServer: closing output");
|
||||
output.writeBytes(response);
|
||||
output.flush();
|
||||
}
|
||||
output.close();
|
||||
xhrReader.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.active = false;
|
||||
//Log.d(LOG_TAG, "CallbackServer.startServer() - EXIT");
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop server.
|
||||
* This stops the thread that the server is running on.
|
||||
*/
|
||||
public void stopServer() {
|
||||
//Log.d(LOG_TAG, "CallbackServer.stopServer()");
|
||||
if (this.active) {
|
||||
this.active = false;
|
||||
|
||||
// Break out of server wait
|
||||
synchronized (this) {
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy
|
||||
*/
|
||||
public void destroy() {
|
||||
this.stopServer();
|
||||
this.stopServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of JavaScript statements.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public int getSize() {
|
||||
synchronized(this) {
|
||||
int size = this.javascript.size();
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next JavaScript statement and remove from list.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String getJavascript() {
|
||||
synchronized(this) {
|
||||
if (this.javascript.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
String statement = this.javascript.remove(0);
|
||||
if (this.javascript.size() == 0) {
|
||||
this.empty = true;
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JavaScript statement to the list.
|
||||
*
|
||||
* @param statement
|
||||
*/
|
||||
public void sendJavascript(String statement) {
|
||||
synchronized (this) {
|
||||
this.javascript.add(statement);
|
||||
this.empty = false;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/* The Following code has been modified from original implementation of URLEncoder */
|
||||
|
||||
/* start */
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get the number of JavaScript statements.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public int getSize() {
|
||||
synchronized (this) {
|
||||
int size = this.javascript.size();
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next JavaScript statement and remove from list.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String getJavascript() {
|
||||
synchronized (this) {
|
||||
if (this.javascript.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
String statement = this.javascript.remove(0);
|
||||
if (this.javascript.size() == 0) {
|
||||
this.empty = true;
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JavaScript statement to the list.
|
||||
*
|
||||
* @param statement
|
||||
*/
|
||||
public void sendJavascript(String statement) {
|
||||
synchronized (this) {
|
||||
this.javascript.add(statement);
|
||||
this.empty = false;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/* The Following code has been modified from original implementation of URLEncoder */
|
||||
|
||||
/* start */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@@ -371,24 +366,24 @@ public class CallbackServer implements Runnable {
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
static final String digits = "0123456789ABCDEF";
|
||||
static final String digits = "0123456789ABCDEF";
|
||||
|
||||
/**
|
||||
* This will encode the return value to JavaScript. We revert the encoding for
|
||||
* common characters that don't require encoding to reduce the size of the string
|
||||
* This will encode the return value to JavaScript. We revert the encoding for
|
||||
* common characters that don't require encoding to reduce the size of the string
|
||||
* being passed to JavaScript.
|
||||
*
|
||||
*
|
||||
* @param s to be encoded
|
||||
* @param enc encoding type
|
||||
* @return encoded string
|
||||
*/
|
||||
public static String encode(String s, String enc) throws UnsupportedEncodingException {
|
||||
public static String encode(String s, String enc) throws UnsupportedEncodingException {
|
||||
if (s == null || enc == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
// check for UnsupportedEncodingException
|
||||
"".getBytes(enc);
|
||||
|
||||
|
||||
// Guess a bit bigger for encoded form
|
||||
StringBuilder buf = new StringBuilder(s.length() + 16);
|
||||
int start = -1;
|
||||
@@ -426,6 +421,6 @@ public class CallbackServer implements Runnable {
|
||||
buf.append(digits.charAt(bytes[j] & 0xf));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* end */
|
||||
}
|
||||
|
||||
@@ -20,12 +20,14 @@ package org.apache.cordova;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
//import org.apache.cordova.api.CordovaInterface;
|
||||
import org.apache.cordova.api.LOG;
|
||||
import org.apache.cordova.api.Plugin;
|
||||
import org.apache.cordova.api.PluginResult;
|
||||
@@ -34,59 +36,78 @@ import org.json.JSONException;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentValues;
|
||||
//import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Bitmap.CompressFormat;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* This class launches the camera view, allows the user to take a picture, closes the camera view,
|
||||
* and returns the captured image. When the camera view is closed, the screen displayed before
|
||||
* and returns the captured image. When the camera view is closed, the screen displayed before
|
||||
* the camera view was shown is redisplayed.
|
||||
*/
|
||||
public class CameraLauncher extends Plugin {
|
||||
public class CameraLauncher extends Plugin implements MediaScannerConnectionClient {
|
||||
|
||||
private static final int DATA_URL = 0; // Return base64 encoded string
|
||||
private static final int FILE_URI = 1; // Return file uri (content://media/external/images/media/2 for Android)
|
||||
|
||||
|
||||
private static final int PHOTOLIBRARY = 0; // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
|
||||
private static final int CAMERA = 1; // Take picture from camera
|
||||
private static final int SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android)
|
||||
|
||||
|
||||
private static final int PICTURE = 0; // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
|
||||
private static final int VIDEO = 1; // allow selection of video only, ONLY RETURNS URL
|
||||
private static final int ALLMEDIA = 2; // allow selection from all media types
|
||||
|
||||
|
||||
private static final int JPEG = 0; // Take a picture of type JPEG
|
||||
private static final int PNG = 1; // Take a picture of type PNG
|
||||
private static final String GET_PICTURE = "Get Picture";
|
||||
private static final String GET_VIDEO = "Get Video";
|
||||
private static final String GET_All = "Get All";
|
||||
|
||||
|
||||
private static final String LOG_TAG = "CameraLauncher";
|
||||
|
||||
|
||||
private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
|
||||
private int targetWidth; // desired width of the image
|
||||
private int targetHeight; // desired height of the image
|
||||
private Uri imageUri; // Uri of captured image
|
||||
private Uri imageUri; // Uri of captured image
|
||||
private int encodingType; // Type of encoding to use
|
||||
private int mediaType; // What type of media to retrieve
|
||||
|
||||
private boolean saveToPhotoAlbum; // Should the picture be saved to the device's photo album
|
||||
|
||||
public String callbackId;
|
||||
private int numPics;
|
||||
|
||||
private MediaScannerConnection conn; // Used to update gallery app with newly-written files
|
||||
|
||||
//This should never be null!
|
||||
//private CordovaInterface cordova;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public CameraLauncher() {
|
||||
}
|
||||
|
||||
// public void setContext(CordovaInterface mCtx) {
|
||||
// super.setContext(mCtx);
|
||||
// if (CordovaInterface.class.isInstance(mCtx))
|
||||
// cordova = (CordovaInterface) mCtx;
|
||||
// else
|
||||
// LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
|
||||
// }
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
@@ -94,13 +115,14 @@ public class CameraLauncher extends Plugin {
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
String result = "";
|
||||
this.callbackId = callbackId;
|
||||
|
||||
|
||||
try {
|
||||
if (action.equals("takePicture")) {
|
||||
int srcType = CAMERA;
|
||||
int destType = FILE_URI;
|
||||
this.saveToPhotoAlbum = false;
|
||||
this.targetHeight = 0;
|
||||
this.targetWidth = 0;
|
||||
this.encodingType = JPEG;
|
||||
@@ -114,7 +136,8 @@ public class CameraLauncher extends Plugin {
|
||||
this.targetHeight = args.getInt(4);
|
||||
this.encodingType = args.getInt(5);
|
||||
this.mediaType = args.getInt(6);
|
||||
|
||||
this.saveToPhotoAlbum = args.getBoolean(9);
|
||||
|
||||
if (srcType == CAMERA) {
|
||||
this.takePicture(destType, encodingType);
|
||||
}
|
||||
@@ -131,53 +154,57 @@ public class CameraLauncher extends Plugin {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Take a picture with the camera.
|
||||
* When an image is captured or the camera view is cancelled, the result is returned
|
||||
* in CordovaActivity.onActivityResult, which forwards the result to this.onActivityResult.
|
||||
*
|
||||
*
|
||||
* The image can either be returned as a base64 string or a URI that points to the file.
|
||||
* To display base64 string in an img tag, set the source to:
|
||||
* img.src="data:image/jpeg;base64,"+result;
|
||||
* or to display URI in an img tag
|
||||
* img.src=result;
|
||||
*
|
||||
*
|
||||
* @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
|
||||
* @param returnType Set the type of image to return.
|
||||
* @param returnType Set the type of image to return.
|
||||
*/
|
||||
public void takePicture(int returnType, int encodingType) {
|
||||
// Save the number of images currently on disk for later
|
||||
this.numPics = queryImgDB().getCount();
|
||||
|
||||
this.numPics = queryImgDB(whichContentStore()).getCount();
|
||||
|
||||
// Display camera
|
||||
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
|
||||
|
||||
|
||||
// Specify file so that large image is captured and returned
|
||||
// TODO: What if there isn't any external storage?
|
||||
File photo = createCaptureFile(encodingType);
|
||||
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
|
||||
this.imageUri = Uri.fromFile(photo);
|
||||
|
||||
this.ctx.startActivityForResult((Plugin) this, intent, (CAMERA+1)*16 + returnType+1);
|
||||
if (this.cordova != null) {
|
||||
this.cordova.startActivityForResult((Plugin) this, intent, (CAMERA + 1) * 16 + returnType + 1);
|
||||
}
|
||||
// else
|
||||
// LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a file in the applications temporary directory based upon the supplied encoding.
|
||||
*
|
||||
*
|
||||
* @param encodingType of the image to be taken
|
||||
* @return a File object pointing to the temporary picture
|
||||
*/
|
||||
private File createCaptureFile(int encodingType) {
|
||||
File photo = null;
|
||||
if (encodingType == JPEG) {
|
||||
photo = new File(DirectoryManager.getTempDirectoryPath(ctx.getContext()), "Pic.jpg");
|
||||
photo = new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), ".Pic.jpg");
|
||||
} else if (encodingType == PNG) {
|
||||
photo = new File(DirectoryManager.getTempDirectoryPath(ctx.getContext()), "Pic.png");
|
||||
photo = new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), ".Pic.png");
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid Encoding Type: " + encodingType);
|
||||
}
|
||||
@@ -186,40 +213,42 @@ public class CameraLauncher extends Plugin {
|
||||
|
||||
/**
|
||||
* Get image from photo library.
|
||||
*
|
||||
*
|
||||
* @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
|
||||
* @param srcType The album to get image from.
|
||||
* @param returnType Set the type of image to return.
|
||||
* @param returnType Set the type of image to return.
|
||||
*/
|
||||
// TODO: Images selected from SDCARD don't display correctly, but from CAMERA ALBUM do!
|
||||
public void getImage(int srcType, int returnType) {
|
||||
Intent intent = new Intent();
|
||||
String title = GET_PICTURE;
|
||||
if (this.mediaType == PICTURE) {
|
||||
intent.setType("image/*");
|
||||
intent.setType("image/*");
|
||||
}
|
||||
else if (this.mediaType == VIDEO) {
|
||||
intent.setType("video/*");
|
||||
intent.setType("video/*");
|
||||
title = GET_VIDEO;
|
||||
}
|
||||
else if (this.mediaType == ALLMEDIA) {
|
||||
// I wanted to make the type 'image/*, video/*' but this does not work on all versions
|
||||
// I wanted to make the type 'image/*, video/*' but this does not work on all versions
|
||||
// of android so I had to go with the wildcard search.
|
||||
intent.setType("*/*");
|
||||
intent.setType("*/*");
|
||||
title = GET_All;
|
||||
}
|
||||
|
||||
|
||||
intent.setAction(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
this.ctx.startActivityForResult((Plugin) this, Intent.createChooser(intent,
|
||||
new String(title)), (srcType+1)*16 + returnType + 1);
|
||||
if (this.cordova != null) {
|
||||
this.cordova.startActivityForResult((Plugin) this, Intent.createChooser(intent,
|
||||
new String(title)), (srcType + 1) * 16 + returnType + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scales the bitmap according to the requested size.
|
||||
*
|
||||
*
|
||||
* @param bitmap The bitmap to scale.
|
||||
* @return Bitmap A new Bitmap object of the same bitmap after scaling.
|
||||
* @return Bitmap A new Bitmap object of the same bitmap after scaling.
|
||||
*/
|
||||
public Bitmap scaleBitmap(Bitmap bitmap) {
|
||||
int newWidth = this.targetWidth;
|
||||
@@ -246,8 +275,8 @@ public class CameraLauncher extends Plugin {
|
||||
// kept and Bitmap.SCALE_TO_FIT specified when scaling, but this
|
||||
// would result in whitespace in the new image.
|
||||
else {
|
||||
double newRatio = newWidth / (double)newHeight;
|
||||
double origRatio = origWidth / (double)origHeight;
|
||||
double newRatio = newWidth / (double) newHeight;
|
||||
double origRatio = origWidth / (double) origHeight;
|
||||
|
||||
if (origRatio > newRatio) {
|
||||
newHeight = (newWidth * origHeight) / origWidth;
|
||||
@@ -255,104 +284,126 @@ public class CameraLauncher extends Plugin {
|
||||
newWidth = (newHeight * origWidth) / origHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Bitmap retval = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
|
||||
bitmap.recycle();
|
||||
System.gc();
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when the camera view exits.
|
||||
*
|
||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
||||
* Called when the camera view exits.
|
||||
*
|
||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
||||
* allowing you to identify who this result came from.
|
||||
* @param resultCode The integer result code returned by the child activity through its setResult().
|
||||
* @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
|
||||
*/
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
|
||||
// Get src and dest types from request code
|
||||
int srcType = (requestCode/16) - 1;
|
||||
int destType = (requestCode % 16) - 1;
|
||||
int rotate = 0;
|
||||
|
||||
// Create an ExifHelper to save the exif data that is lost during compression
|
||||
ExifHelper exif = new ExifHelper();
|
||||
try {
|
||||
if (this.encodingType == JPEG) {
|
||||
exif.createInFile(DirectoryManager.getTempDirectoryPath(ctx.getContext()) + "/Pic.jpg");
|
||||
exif.readExifData();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Get src and dest types from request code
|
||||
int srcType = (requestCode / 16) - 1;
|
||||
int destType = (requestCode % 16) - 1;
|
||||
int rotate = 0;
|
||||
|
||||
// Create an ExifHelper to save the exif data that is lost during compression
|
||||
ExifHelper exif = new ExifHelper();
|
||||
try {
|
||||
if (this.encodingType == JPEG) {
|
||||
exif.createInFile(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/.Pic.jpg");
|
||||
exif.readExifData();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// If CAMERA
|
||||
if (srcType == CAMERA) {
|
||||
// If image available
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
try {
|
||||
// Read in bitmap of captured image
|
||||
Bitmap bitmap;
|
||||
try {
|
||||
bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
|
||||
} catch (FileNotFoundException e) {
|
||||
Uri uri = intent.getData();
|
||||
android.content.ContentResolver resolver = this.ctx.getContentResolver();
|
||||
bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
||||
}
|
||||
Bitmap bitmap = null;
|
||||
|
||||
bitmap = scaleBitmap(bitmap);
|
||||
|
||||
// If sending base64 image back
|
||||
if (destType == DATA_URL) {
|
||||
bitmap = scaleBitmap(getBitmapFromResult(intent));
|
||||
|
||||
this.processPicture(bitmap);
|
||||
checkForDuplicateImage(DATA_URL);
|
||||
}
|
||||
|
||||
// If sending filename back
|
||||
else if (destType == FILE_URI){
|
||||
// Create entry in media store for image
|
||||
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
|
||||
Uri uri = null;
|
||||
try {
|
||||
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
LOG.d(LOG_TAG, "Can't write to external media storage.");
|
||||
else if (destType == FILE_URI) {
|
||||
Uri uri;
|
||||
if (!this.saveToPhotoAlbum) {
|
||||
uri = Uri.fromFile(new File("/data/data/" + this.cordova.getActivity().getPackageName() + "/", (new File(FileUtils.stripFileProtocol(this.imageUri.toString()))).getName()));
|
||||
} else {
|
||||
// Create entry in media store for image
|
||||
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
|
||||
|
||||
try {
|
||||
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
LOG.d(LOG_TAG, "Can't write to internal media storage.");
|
||||
this.failPicture("Error capturing image - no media storage found.");
|
||||
return;
|
||||
uri = this.cordova.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
LOG.d(LOG_TAG, "Can't write to external media storage.");
|
||||
try {
|
||||
uri = this.cordova.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
LOG.d(LOG_TAG, "Can't write to internal media storage.");
|
||||
this.failPicture("Error capturing image - no media storage found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add compressed version of captured image to returned media store Uri
|
||||
OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
|
||||
os.close();
|
||||
|
||||
// Restore exif data to file
|
||||
if (this.encodingType == JPEG) {
|
||||
exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
|
||||
exif.writeExifData();
|
||||
}
|
||||
// If all this is true we shouldn't compress the image.
|
||||
if (this.targetHeight == -1 && this.targetWidth == -1 && this.mQuality == 100) {
|
||||
FileInputStream fis = new FileInputStream(FileUtils.stripFileProtocol(imageUri.toString()));
|
||||
OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
|
||||
byte[] buffer = new byte[4096];
|
||||
int len;
|
||||
while ((len = fis.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, len);
|
||||
}
|
||||
os.flush();
|
||||
os.close();
|
||||
fis.close();
|
||||
|
||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
||||
} else {
|
||||
|
||||
bitmap = scaleBitmap(getBitmapFromResult(intent));
|
||||
|
||||
// Add compressed version of captured image to returned media store Uri
|
||||
OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
|
||||
os.close();
|
||||
|
||||
// Restore exif data to file
|
||||
|
||||
if (this.encodingType == JPEG) {
|
||||
String exifPath;
|
||||
if (this.saveToPhotoAlbum) {
|
||||
exifPath = FileUtils.getRealPathFromURI(uri, this.cordova);
|
||||
} else {
|
||||
exifPath = uri.getPath();
|
||||
}
|
||||
exif.createOutFile(exifPath);
|
||||
exif.writeExifData();
|
||||
}
|
||||
|
||||
}
|
||||
// Send Uri back to JavaScript for viewing image
|
||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
||||
}
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
System.gc();
|
||||
|
||||
checkForDuplicateImage(FILE_URI);
|
||||
this.cleanup(FILE_URI, this.imageUri, bitmap);
|
||||
bitmap = null;
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
this.failPicture("Error capturing image.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If cancelled
|
||||
@@ -365,38 +416,38 @@ public class CameraLauncher extends Plugin {
|
||||
this.failPicture("Did not complete!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If retrieving photo from library
|
||||
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
Uri uri = intent.getData();
|
||||
android.content.ContentResolver resolver = this.ctx.getContentResolver();
|
||||
|
||||
// If you ask for video or all media type you will automatically get back a file URI
|
||||
android.content.ContentResolver resolver = this.cordova.getActivity().getContentResolver();
|
||||
|
||||
// If you ask for video or all media type you will automatically get back a file URI
|
||||
// and there will be no attempt to resize any returned data
|
||||
if (this.mediaType != PICTURE) {
|
||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
||||
}
|
||||
else {
|
||||
// If sending base64 image back
|
||||
if (destType == DATA_URL) {
|
||||
try {
|
||||
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
||||
String[] cols = { MediaStore.Images.Media.ORIENTATION };
|
||||
Cursor cursor = this.ctx.getContentResolver().query(intent.getData(),
|
||||
cols,
|
||||
null, null, null);
|
||||
if (cursor != null) {
|
||||
cursor.moveToPosition(0);
|
||||
rotate = cursor.getInt(0);
|
||||
cursor.close();
|
||||
}
|
||||
if (rotate != 0) {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.setRotate(rotate);
|
||||
bitmap = bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
bitmap = scaleBitmap(bitmap);
|
||||
String[] cols = { MediaStore.Images.Media.ORIENTATION };
|
||||
Cursor cursor = this.cordova.getActivity().getContentResolver().query(intent.getData(),
|
||||
cols,
|
||||
null, null, null);
|
||||
if (cursor != null) {
|
||||
cursor.moveToPosition(0);
|
||||
rotate = cursor.getInt(0);
|
||||
cursor.close();
|
||||
}
|
||||
if (rotate != 0) {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.setRotate(rotate);
|
||||
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
bitmap = scaleBitmap(bitmap);
|
||||
this.processPicture(bitmap);
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
@@ -406,7 +457,7 @@ public class CameraLauncher extends Plugin {
|
||||
this.failPicture("Error retrieving image.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If sending filename back
|
||||
else if (destType == FILE_URI) {
|
||||
// Do we need to scale the returned file
|
||||
@@ -414,22 +465,22 @@ public class CameraLauncher extends Plugin {
|
||||
try {
|
||||
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
||||
bitmap = scaleBitmap(bitmap);
|
||||
|
||||
String fileName = DirectoryManager.getTempDirectoryPath(ctx.getContext()) + "/resize.jpg";
|
||||
OutputStream os = new FileOutputStream(fileName);
|
||||
|
||||
String fileName = DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/resize.jpg";
|
||||
OutputStream os = new FileOutputStream(fileName);
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
|
||||
os.close();
|
||||
|
||||
|
||||
// Restore exif data to file
|
||||
if (this.encodingType == JPEG) {
|
||||
exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
|
||||
exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.cordova));
|
||||
exif.writeExifData();
|
||||
}
|
||||
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
|
||||
// The resized image is cached by the app in order to get around this and not have to delete you
|
||||
|
||||
// The resized image is cached by the app in order to get around this and not have to delete you
|
||||
// application cache I'm adding the current system time to the end of the file url.
|
||||
this.success(new PluginResult(PluginResult.Status.OK, ("file://" + fileName + "?" + System.currentTimeMillis())), this.callbackId);
|
||||
System.gc();
|
||||
@@ -439,56 +490,98 @@ public class CameraLauncher extends Plugin {
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (resultCode == Activity.RESULT_CANCELED) {
|
||||
this.failPicture("Selection cancelled.");
|
||||
this.failPicture("Selection cancelled.");
|
||||
}
|
||||
else {
|
||||
this.failPicture("Selection did not complete!");
|
||||
this.failPicture("Selection did not complete!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap getBitmapFromResult(Intent intent)
|
||||
throws IOException, FileNotFoundException {
|
||||
Bitmap bitmap = null;
|
||||
try {
|
||||
bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getActivity().getContentResolver(), imageUri);
|
||||
} catch (FileNotFoundException e) {
|
||||
Uri uri = intent.getData();
|
||||
android.content.ContentResolver resolver = this.ctx.getActivity().getContentResolver();
|
||||
bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cursor that can be used to determine how many images we have.
|
||||
*
|
||||
*
|
||||
* @return a cursor
|
||||
*/
|
||||
private Cursor queryImgDB() {
|
||||
return this.ctx.getContentResolver().query(
|
||||
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
private Cursor queryImgDB(Uri contentStore) {
|
||||
return this.cordova.getActivity().getContentResolver().query(
|
||||
contentStore,
|
||||
new String[] { MediaStore.Images.Media._ID },
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up after picture taking. Checking for duplicates and that kind of stuff.
|
||||
*/
|
||||
private void cleanup(int imageType, Uri oldImage, Bitmap bitmap) {
|
||||
bitmap.recycle();
|
||||
|
||||
// Clean up initial camera-written image file.
|
||||
(new File(FileUtils.stripFileProtocol(oldImage.toString()))).delete();
|
||||
|
||||
checkForDuplicateImage(imageType);
|
||||
// Scan for the gallery to update pic refs in gallery
|
||||
this.scanForGallery();
|
||||
|
||||
System.gc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to find out if we are in a situation where the Camera Intent adds to images
|
||||
* to the content store. If we are using a FILE_URI and the number of images in the DB
|
||||
* to the content store. If we are using a FILE_URI and the number of images in the DB
|
||||
* increases by 2 we have a duplicate, when using a DATA_URL the number is 1.
|
||||
*
|
||||
*
|
||||
* @param type FILE_URI or DATA_URL
|
||||
*/
|
||||
private void checkForDuplicateImage(int type) {
|
||||
int diff = 1;
|
||||
Cursor cursor = queryImgDB();
|
||||
Uri contentStore = whichContentStore();
|
||||
Cursor cursor = queryImgDB(contentStore);
|
||||
int currentNumOfImages = cursor.getCount();
|
||||
|
||||
|
||||
if (type == FILE_URI) {
|
||||
diff = 2;
|
||||
}
|
||||
|
||||
|
||||
// delete the duplicate file if the difference is 2 for file URI or 1 for Data URL
|
||||
if ((currentNumOfImages - numPics) == diff) {
|
||||
cursor.moveToLast();
|
||||
int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID))) - 1;
|
||||
Uri uri = Uri.parse(MediaStore.Images.Media.EXTERNAL_CONTENT_URI + "/" + id);
|
||||
this.ctx.getContentResolver().delete(uri, null, null);
|
||||
int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID))) - 1;
|
||||
Uri uri = Uri.parse(contentStore + "/" + id);
|
||||
this.cordova.getActivity().getContentResolver().delete(uri, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we are storing the images in internal or external storage
|
||||
* @return Uri
|
||||
*/
|
||||
private Uri whichContentStore() {
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
return android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||
} else {
|
||||
return android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,31 +590,50 @@ public class CameraLauncher extends Plugin {
|
||||
*
|
||||
* @param bitmap
|
||||
*/
|
||||
public void processPicture(Bitmap bitmap) {
|
||||
public void processPicture(Bitmap bitmap) {
|
||||
ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream();
|
||||
try {
|
||||
if (bitmap.compress(CompressFormat.JPEG, mQuality, jpeg_data)) {
|
||||
byte[] code = jpeg_data.toByteArray();
|
||||
byte[] code = jpeg_data.toByteArray();
|
||||
byte[] output = Base64.encodeBase64(code);
|
||||
String js_out = new String(output);
|
||||
this.success(new PluginResult(PluginResult.Status.OK, js_out), this.callbackId);
|
||||
js_out = null;
|
||||
output = null;
|
||||
code = null;
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.failPicture("Error compressing image.");
|
||||
}
|
||||
}
|
||||
jpeg_data = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send error message to JavaScript.
|
||||
*
|
||||
*
|
||||
* @param err
|
||||
*/
|
||||
public void failPicture(String err) {
|
||||
this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
|
||||
}
|
||||
|
||||
private void scanForGallery() {
|
||||
if(this.conn!=null) this.conn.disconnect();
|
||||
this.conn = new MediaScannerConnection(this.ctx.getActivity().getApplicationContext(), this);
|
||||
conn.connect();
|
||||
}
|
||||
|
||||
public void onMediaScannerConnected() {
|
||||
try{
|
||||
this.conn.scanFile(this.imageUri.toString(), "image/*");
|
||||
} catch (java.lang.IllegalStateException e){
|
||||
e.printStackTrace();
|
||||
LOG.d(LOG_TAG, "Can;t scan file in MediaScanner aftering taking picture");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void onScanCompleted(String path, Uri uri) {
|
||||
this.conn.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package org.apache.cordova;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
@@ -32,36 +33,48 @@ import org.json.JSONObject;
|
||||
import android.app.Activity;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
public class Capture extends Plugin {
|
||||
|
||||
private static final String VIDEO_3GPP = "video/3gpp";
|
||||
private static final String VIDEO_MP4 = "video/mp4";
|
||||
private static final String VIDEO_MP4 = "video/mp4";
|
||||
private static final String AUDIO_3GPP = "audio/3gpp";
|
||||
private static final String IMAGE_JPEG = "image/jpeg";
|
||||
|
||||
|
||||
private static final int CAPTURE_AUDIO = 0; // Constant for capture audio
|
||||
private static final int CAPTURE_IMAGE = 1; // Constant for capture image
|
||||
private static final int CAPTURE_VIDEO = 2; // Constant for capture video
|
||||
private static final String LOG_TAG = "Capture";
|
||||
|
||||
|
||||
private static final int CAPTURE_INTERNAL_ERR = 0;
|
||||
private static final int CAPTURE_APPLICATION_BUSY = 1;
|
||||
private static final int CAPTURE_INVALID_ARGUMENT = 2;
|
||||
// private static final int CAPTURE_APPLICATION_BUSY = 1;
|
||||
// private static final int CAPTURE_INVALID_ARGUMENT = 2;
|
||||
private static final int CAPTURE_NO_MEDIA_FILES = 3;
|
||||
private static final int CAPTURE_NOT_SUPPORTED = 20;
|
||||
|
||||
|
||||
private String callbackId; // The ID of the callback to be invoked with our result
|
||||
private long limit; // the number of pics/vids/clips to take
|
||||
private double duration; // optional duration parameter for video recording
|
||||
private JSONArray results; // The array of results to be returned to the user
|
||||
private Uri imageUri; // Uri of captured image
|
||||
private Uri imageUri; // Uri of captured image
|
||||
private int numPics; // Number of pictures before capture activity
|
||||
|
||||
//private CordovaInterface cordova;
|
||||
|
||||
// public void setContext(Context mCtx)
|
||||
// {
|
||||
// if (CordovaInterface.class.isInstance(mCtx))
|
||||
// cordova = (CordovaInterface) mCtx;
|
||||
// else
|
||||
// LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
|
||||
// }
|
||||
|
||||
@Override
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
@@ -69,7 +82,7 @@ public class Capture extends Plugin {
|
||||
this.limit = 1;
|
||||
this.duration = 0.0f;
|
||||
this.results = new JSONArray();
|
||||
|
||||
|
||||
JSONObject options = args.optJSONObject(0);
|
||||
if (options != null) {
|
||||
limit = options.optLong("limit", 1);
|
||||
@@ -91,9 +104,9 @@ public class Capture extends Plugin {
|
||||
this.captureImage();
|
||||
}
|
||||
else if (action.equals("captureVideo")) {
|
||||
this.captureVideo(duration);
|
||||
this.captureVideo(duration);
|
||||
}
|
||||
|
||||
|
||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
r.setKeepCallback(true);
|
||||
return r;
|
||||
@@ -101,7 +114,7 @@ public class Capture extends Plugin {
|
||||
|
||||
/**
|
||||
* Provides the media data file data depending on it's mime type
|
||||
*
|
||||
*
|
||||
* @param filePath path to the file
|
||||
* @param mimeType of the file
|
||||
* @return a MediaFileData object
|
||||
@@ -122,7 +135,7 @@ public class Capture extends Plugin {
|
||||
mimeType = FileUtils.getMimeType(filePath);
|
||||
}
|
||||
Log.d(LOG_TAG, "Mime type = " + mimeType);
|
||||
|
||||
|
||||
if (mimeType.equals(IMAGE_JPEG) || filePath.endsWith(".jpg")) {
|
||||
obj = getImageData(filePath, obj);
|
||||
}
|
||||
@@ -132,8 +145,7 @@ public class Capture extends Plugin {
|
||||
else if (mimeType.equals(VIDEO_3GPP) || mimeType.equals(VIDEO_MP4)) {
|
||||
obj = getAudioVideoData(filePath, obj, true);
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
} catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "Error: setting media file data object");
|
||||
}
|
||||
return obj;
|
||||
@@ -141,23 +153,24 @@ public class Capture extends Plugin {
|
||||
|
||||
/**
|
||||
* Get the Image specific attributes
|
||||
*
|
||||
*
|
||||
* @param filePath path to the file
|
||||
* @param obj represents the Media File Data
|
||||
* @return a JSONObject that represents the Media File Data
|
||||
* @throws JSONException
|
||||
*/
|
||||
private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException {
|
||||
Bitmap bitmap = BitmapFactory.decodeFile(FileUtils.stripFileProtocol(filePath));
|
||||
obj.put("height", bitmap.getHeight());
|
||||
obj.put("width", bitmap.getWidth());
|
||||
bitmap.recycle();
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(FileUtils.stripFileProtocol(filePath), options);
|
||||
obj.put("height", options.outHeight);
|
||||
obj.put("width", options.outWidth);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Image specific attributes
|
||||
*
|
||||
*
|
||||
* @param filePath path to the file
|
||||
* @param obj represents the Media File Data
|
||||
* @param video if true get video attributes as well
|
||||
@@ -169,15 +182,14 @@ public class Capture extends Plugin {
|
||||
try {
|
||||
player.setDataSource(filePath);
|
||||
player.prepare();
|
||||
obj.put("duration", player.getDuration()/1000);
|
||||
obj.put("duration", player.getDuration() / 1000);
|
||||
if (video) {
|
||||
obj.put("height", player.getVideoHeight());
|
||||
obj.put("width", player.getVideoWidth());
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
} catch (IOException e) {
|
||||
Log.d(LOG_TAG, "Error: loading video file");
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -187,21 +199,24 @@ public class Capture extends Plugin {
|
||||
private void captureAudio() {
|
||||
Intent intent = new Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION);
|
||||
|
||||
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_AUDIO);
|
||||
this.cordova.startActivityForResult((Plugin) this, intent, CAPTURE_AUDIO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up an intent to capture images. Result handled by onActivityResult()
|
||||
*/
|
||||
private void captureImage() {
|
||||
// Save the number of images currently on disk for later
|
||||
this.numPics = queryImgDB(whichContentStore()).getCount();
|
||||
|
||||
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
|
||||
// Specify file so that large image is captured and returned
|
||||
File photo = new File(DirectoryManager.getTempDirectoryPath(ctx.getContext()), "Capture.jpg");
|
||||
File photo = new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), "Capture.jpg");
|
||||
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
|
||||
this.imageUri = Uri.fromFile(photo);
|
||||
|
||||
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_IMAGE);
|
||||
this.cordova.startActivityForResult((Plugin) this, intent, CAPTURE_IMAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,18 +226,18 @@ public class Capture extends Plugin {
|
||||
Intent intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);
|
||||
// Introduced in API 8
|
||||
//intent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT, duration);
|
||||
|
||||
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_VIDEO);
|
||||
|
||||
this.cordova.startActivityForResult((Plugin) this, intent, CAPTURE_VIDEO);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when the video view exits.
|
||||
*
|
||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
||||
* Called when the video view exits.
|
||||
*
|
||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
||||
* allowing you to identify who this result came from.
|
||||
* @param resultCode The integer result code returned by the child activity through its setResult().
|
||||
* @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
|
||||
* @throws JSONException
|
||||
* @throws JSONException
|
||||
*/
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
|
||||
@@ -248,48 +263,39 @@ public class Capture extends Plugin {
|
||||
// It crashes in the emulator and on my phone with a null pointer exception
|
||||
// To work around it I had to grab the code from CameraLauncher.java
|
||||
try {
|
||||
// Create an ExifHelper to save the exif data that is lost during compression
|
||||
ExifHelper exif = new ExifHelper();
|
||||
exif.createInFile(DirectoryManager.getTempDirectoryPath(ctx.getContext()) + "/Capture.jpg");
|
||||
exif.readExifData();
|
||||
|
||||
// Read in bitmap of captured image
|
||||
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
|
||||
|
||||
// Create entry in media store for image
|
||||
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, IMAGE_JPEG);
|
||||
Uri uri = null;
|
||||
try {
|
||||
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
||||
uri = this.cordova.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
LOG.d(LOG_TAG, "Can't write to external media storage.");
|
||||
try {
|
||||
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
|
||||
uri = this.cordova.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
LOG.d(LOG_TAG, "Can't write to internal media storage.");
|
||||
LOG.d(LOG_TAG, "Can't write to internal media storage.");
|
||||
this.fail(createErrorObject(CAPTURE_INTERNAL_ERR, "Error capturing image - no media storage found."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add compressed version of captured image to returned media store Uri
|
||||
OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
|
||||
FileInputStream fis = new FileInputStream(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/Capture.jpg");
|
||||
OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
|
||||
byte[] buffer = new byte[4096];
|
||||
int len;
|
||||
while ((len = fis.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, len);
|
||||
}
|
||||
os.flush();
|
||||
os.close();
|
||||
fis.close();
|
||||
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
System.gc();
|
||||
|
||||
// Restore exif data to file
|
||||
exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
|
||||
exif.writeExifData();
|
||||
|
||||
// Add image to results
|
||||
results.put(createMediaFile(uri));
|
||||
|
||||
|
||||
checkForDuplicateImage();
|
||||
|
||||
if (results.length() >= limit) {
|
||||
// Send Uri back to JavaScript for viewing image
|
||||
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
|
||||
@@ -320,7 +326,7 @@ public class Capture extends Plugin {
|
||||
else if (resultCode == Activity.RESULT_CANCELED) {
|
||||
// If we have partial results send them back to the user
|
||||
if (results.length() > 0) {
|
||||
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
|
||||
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
|
||||
}
|
||||
// user canceled the action
|
||||
else {
|
||||
@@ -331,7 +337,7 @@ public class Capture extends Plugin {
|
||||
else {
|
||||
// If we have partial results send them back to the user
|
||||
if (results.length() > 0) {
|
||||
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
|
||||
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
|
||||
}
|
||||
// something bad happened
|
||||
else {
|
||||
@@ -342,43 +348,42 @@ public class Capture extends Plugin {
|
||||
|
||||
/**
|
||||
* Creates a JSONObject that represents a File from the Uri
|
||||
*
|
||||
*
|
||||
* @param data the Uri of the audio/image/video
|
||||
* @return a JSONObject that represents a File
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
private JSONObject createMediaFile(Uri data){
|
||||
File fp = new File(FileUtils.getRealPathFromURI(data, this.ctx));
|
||||
private JSONObject createMediaFile(Uri data) {
|
||||
File fp = new File(FileUtils.getRealPathFromURI(data, this.cordova));
|
||||
JSONObject obj = new JSONObject();
|
||||
|
||||
try {
|
||||
try {
|
||||
// File properties
|
||||
obj.put("name", fp.getName());
|
||||
obj.put("fullPath", "file://" + fp.getAbsolutePath());
|
||||
|
||||
// Because of an issue with MimeTypeMap.getMimeTypeFromExtension() all .3gpp files
|
||||
// are reported as video/3gpp. I'm doing this hacky check of the URI to see if it
|
||||
// Because of an issue with MimeTypeMap.getMimeTypeFromExtension() all .3gpp files
|
||||
// are reported as video/3gpp. I'm doing this hacky check of the URI to see if it
|
||||
// is stored in the audio or video content store.
|
||||
if (fp.getAbsoluteFile().toString().endsWith(".3gp") || fp.getAbsoluteFile().toString().endsWith(".3gpp")) {
|
||||
if (data.toString().contains("/audio/")) {
|
||||
obj.put("type", AUDIO_3GPP);
|
||||
obj.put("type", AUDIO_3GPP);
|
||||
} else {
|
||||
obj.put("type", VIDEO_3GPP);
|
||||
}
|
||||
obj.put("type", VIDEO_3GPP);
|
||||
}
|
||||
} else {
|
||||
obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
|
||||
obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
|
||||
}
|
||||
|
||||
|
||||
obj.put("lastModifiedDate", fp.lastModified());
|
||||
obj.put("size", fp.length());
|
||||
} catch (JSONException e) {
|
||||
// this will never happen
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
private JSONObject createErrorObject(int code, String message) {
|
||||
JSONObject obj = new JSONObject();
|
||||
try {
|
||||
@@ -392,10 +397,55 @@ public class Capture extends Plugin {
|
||||
|
||||
/**
|
||||
* Send error message to JavaScript.
|
||||
*
|
||||
*
|
||||
* @param err
|
||||
*/
|
||||
public void fail(JSONObject err) {
|
||||
this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a cursor that can be used to determine how many images we have.
|
||||
*
|
||||
* @return a cursor
|
||||
*/
|
||||
private Cursor queryImgDB(Uri contentStore) {
|
||||
return this.cordova.getActivity().getContentResolver().query(
|
||||
contentStore,
|
||||
new String[] { MediaStore.Images.Media._ID },
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to find out if we are in a situation where the Camera Intent adds to images
|
||||
* to the content store.
|
||||
*/
|
||||
private void checkForDuplicateImage() {
|
||||
Uri contentStore = whichContentStore();
|
||||
Cursor cursor = queryImgDB(contentStore);
|
||||
int currentNumOfImages = cursor.getCount();
|
||||
|
||||
// delete the duplicate file if the difference is 2
|
||||
if ((currentNumOfImages - numPics) == 2) {
|
||||
cursor.moveToLast();
|
||||
int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID))) - 1;
|
||||
Uri uri = Uri.parse(contentStore + "/" + id);
|
||||
this.cordova.getActivity().getContentResolver().delete(uri, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we are storing the images in internal or external storage
|
||||
* @return Uri
|
||||
*/
|
||||
private Uri whichContentStore() {
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
return android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||
} else {
|
||||
return android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
@@ -43,18 +42,18 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
public static int STARTING = 1;
|
||||
public static int RUNNING = 2;
|
||||
public static int ERROR_FAILED_TO_START = 3;
|
||||
|
||||
|
||||
public long TIMEOUT = 30000; // Timeout in msec to shut off listener
|
||||
|
||||
|
||||
int status; // status of listener
|
||||
float heading; // most recent heading value
|
||||
long timeStamp; // time of most recent value
|
||||
long lastAccessTime; // time the value was last retrieved
|
||||
int accuracy; // accuracy of the sensor
|
||||
|
||||
|
||||
private SensorManager sensorManager;// Sensor manager
|
||||
Sensor mSensor; // Compass sensor returned by sensor manager
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -67,17 +66,17 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*
|
||||
* @param cordova The context of the main Activity.
|
||||
*/
|
||||
public void setContext(CordovaInterface ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
|
||||
public void setContext(CordovaInterface cordova) {
|
||||
super.setContext(cordova);
|
||||
this.sensorManager = (SensorManager) cordova.getActivity().getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
@@ -85,8 +84,8 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("start")) {
|
||||
this.start();
|
||||
@@ -116,7 +115,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
}
|
||||
}
|
||||
if (timeout == 0) {
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, CompassListener.ERROR_FAILED_TO_START);
|
||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, CompassListener.ERROR_FAILED_TO_START);
|
||||
}
|
||||
}
|
||||
return new PluginResult(status, getCompassHeading());
|
||||
@@ -140,7 +139,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
@@ -159,7 +158,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when listener is to be shut down and object is being destroyed.
|
||||
*/
|
||||
@@ -173,17 +172,18 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
|
||||
/**
|
||||
* Start listening for compass sensor.
|
||||
*
|
||||
*
|
||||
* @return status of listener
|
||||
*/
|
||||
public int start() {
|
||||
|
||||
|
||||
// If already starting or running, then just return
|
||||
if ((this.status == CompassListener.RUNNING) || (this.status == CompassListener.STARTING)) {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
// Get compass sensor from sensor manager
|
||||
@SuppressWarnings("deprecation")
|
||||
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
|
||||
|
||||
// If found, then register as listener
|
||||
@@ -198,10 +198,10 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
else {
|
||||
this.setStatus(CompassListener.ERROR_FAILED_TO_START);
|
||||
}
|
||||
|
||||
|
||||
return this.status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop listening to compass sensor.
|
||||
*/
|
||||
@@ -211,15 +211,14 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
}
|
||||
this.setStatus(CompassListener.STOPPED);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Sensor listener event.
|
||||
*
|
||||
*
|
||||
* @param SensorEvent event
|
||||
*/
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
@@ -237,38 +236,38 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get status of compass sensor.
|
||||
*
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
public int getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the most recent compass heading.
|
||||
*
|
||||
*
|
||||
* @return heading
|
||||
*/
|
||||
public float getHeading() {
|
||||
this.lastAccessTime = System.currentTimeMillis();
|
||||
return this.heading;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the timeout to turn off compass sensor if getHeading() hasn't been called.
|
||||
*
|
||||
*
|
||||
* @param timeout Timeout in msec.
|
||||
*/
|
||||
public void setTimeout(long timeout) {
|
||||
this.TIMEOUT = timeout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the timeout to turn off compass sensor if getHeading() hasn't been called.
|
||||
*
|
||||
*
|
||||
* @return timeout in msec
|
||||
*/
|
||||
public long getTimeout() {
|
||||
@@ -285,23 +284,23 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
||||
|
||||
/**
|
||||
* Create the CompassHeading JSON object to be returned to JavaScript
|
||||
*
|
||||
*
|
||||
* @return a compass heading
|
||||
*/
|
||||
private JSONObject getCompassHeading() {
|
||||
JSONObject obj = new JSONObject();
|
||||
|
||||
|
||||
try {
|
||||
obj.put("magneticHeading", this.getHeading());
|
||||
obj.put("trueHeading", this.getHeading());
|
||||
// Since the magnetic and true heading are always the same our and accuracy
|
||||
// Since the magnetic and true heading are always the same our and accuracy
|
||||
// is defined as the difference between true and magnetic always return zero
|
||||
obj.put("headingAccuracy", 0);
|
||||
obj.put("timestamp", this.timeStamp);
|
||||
} catch (JSONException e) {
|
||||
// Should never happen
|
||||
}
|
||||
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import org.apache.cordova.api.CordovaInterface;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@@ -34,15 +35,15 @@ import org.json.JSONObject;
|
||||
* Eclair or higher, we want to use {@link ContactAccessorSdk5}.
|
||||
*/
|
||||
public abstract class ContactAccessor {
|
||||
|
||||
|
||||
protected final String LOG_TAG = "ContactsAccessor";
|
||||
protected Context mApp;
|
||||
protected CordovaInterface mApp;
|
||||
protected WebView mView;
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if the data associated with the key is required to
|
||||
* Check to see if the data associated with the key is required to
|
||||
* be populated in the Contact object.
|
||||
* @param key
|
||||
* @param key
|
||||
* @param map created by running buildPopulationSet.
|
||||
* @return true if the key data is required
|
||||
*/
|
||||
@@ -50,7 +51,7 @@ public abstract class ContactAccessor {
|
||||
Boolean retVal = map.get(key);
|
||||
return (retVal == null) ? false : retVal.booleanValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a hash map of what data needs to be populated in the Contact object
|
||||
* @param fields the list of fields to populate
|
||||
@@ -58,7 +59,7 @@ public abstract class ContactAccessor {
|
||||
*/
|
||||
protected HashMap<String,Boolean> buildPopulationSet(JSONArray fields) {
|
||||
HashMap<String,Boolean> map = new HashMap<String,Boolean>();
|
||||
|
||||
|
||||
String key;
|
||||
try {
|
||||
if (fields.length() == 1 && fields.getString(0).equals("*")) {
|
||||
@@ -75,7 +76,7 @@ public abstract class ContactAccessor {
|
||||
map.put("urls", true);
|
||||
map.put("photos", true);
|
||||
map.put("categories", true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i=0; i<fields.length(); i++) {
|
||||
key = fields.getString(i);
|
||||
@@ -121,18 +122,18 @@ public abstract class ContactAccessor {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.e(LOG_TAG, e.getMessage(), e);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenience method to get a string from a JSON object. Saves a
|
||||
* Convenience method to get a string from a JSON object. Saves a
|
||||
* lot of try/catch writing.
|
||||
* If the property is not found in the object null will be returned.
|
||||
*
|
||||
*
|
||||
* @param obj contact object to search
|
||||
* @param property to be looked up
|
||||
* @return The value of the property
|
||||
@@ -147,10 +148,10 @@ public abstract class ContactAccessor {
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "Could not get = " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -167,7 +168,7 @@ public abstract class ContactAccessor {
|
||||
|
||||
/**
|
||||
* Handles searching through SDK-specific contacts API.
|
||||
* @throws JSONException
|
||||
* @throws JSONException
|
||||
*/
|
||||
public abstract JSONObject getContactById(String id) throws JSONException;
|
||||
|
||||
@@ -175,8 +176,8 @@ public abstract class ContactAccessor {
|
||||
* Handles removing a contact from the database.
|
||||
*/
|
||||
public abstract boolean remove(String id);
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* A class that represents the where clause to be used in the database query
|
||||
*/
|
||||
class WhereOptions {
|
||||
|
||||
@@ -46,7 +46,7 @@ public class ContactManager extends Plugin {
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
@@ -57,7 +57,7 @@ public class ContactManager extends Plugin {
|
||||
String result = "";
|
||||
|
||||
/**
|
||||
* Check to see if we are on an Android 1.X device. If we are return an error as we
|
||||
* Check to see if we are on an Android 1.X device. If we are return an error as we
|
||||
* do not support this as of Cordova 1.0.
|
||||
*/
|
||||
if (android.os.Build.VERSION.RELEASE.startsWith("1.")) {
|
||||
@@ -69,7 +69,7 @@ public class ContactManager extends Plugin {
|
||||
* older phones.
|
||||
*/
|
||||
if (this.contactAccessor == null) {
|
||||
this.contactAccessor = new ContactAccessorSdk5(this.webView, this.ctx.getContext());
|
||||
this.contactAccessor = new ContactAccessorSdk5(this.webView, this.cordova);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -17,16 +17,18 @@
|
||||
under the License.
|
||||
*/
|
||||
package org.apache.cordova;
|
||||
|
||||
import org.apache.cordova.api.CordovaInterface;
|
||||
import org.apache.cordova.api.LOG;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
|
||||
//import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
//import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
//import android.view.View;
|
||||
import android.webkit.ConsoleMessage;
|
||||
import android.webkit.JsPromptResult;
|
||||
import android.webkit.JsResult;
|
||||
@@ -40,24 +42,44 @@ import android.widget.EditText;
|
||||
* This class is the WebChromeClient that implements callbacks for our web view.
|
||||
*/
|
||||
public class CordovaChromeClient extends WebChromeClient {
|
||||
|
||||
|
||||
private String TAG = "CordovaLog";
|
||||
private long MAX_QUOTA = 100 * 1024 * 1024;
|
||||
private DroidGap ctx;
|
||||
|
||||
private CordovaInterface cordova;
|
||||
private CordovaWebView appView;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param cordova
|
||||
*/
|
||||
public CordovaChromeClient(CordovaInterface cordova) {
|
||||
this.cordova = cordova;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ctx
|
||||
* @param app
|
||||
*/
|
||||
public CordovaChromeClient(Context ctx) {
|
||||
this.ctx = (DroidGap) ctx;
|
||||
public CordovaChromeClient(CordovaInterface ctx, CordovaWebView app) {
|
||||
this.cordova = ctx;
|
||||
this.appView = app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param view
|
||||
*/
|
||||
public void setWebView(CordovaWebView view) {
|
||||
this.appView = view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the client to display a javascript alert dialog.
|
||||
*
|
||||
*
|
||||
* @param view
|
||||
* @param url
|
||||
* @param message
|
||||
@@ -65,43 +87,43 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
*/
|
||||
@Override
|
||||
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx);
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(this.cordova.getActivity());
|
||||
dlg.setMessage(message);
|
||||
dlg.setTitle("Alert");
|
||||
//Don't let alerts break the back button
|
||||
dlg.setCancelable(true);
|
||||
dlg.setPositiveButton(android.R.string.ok,
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
result.confirm();
|
||||
}
|
||||
});
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
result.confirm();
|
||||
}
|
||||
});
|
||||
dlg.setOnCancelListener(
|
||||
new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
result.confirm();
|
||||
}
|
||||
});
|
||||
new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
result.confirm();
|
||||
}
|
||||
});
|
||||
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
|
||||
//DO NOTHING
|
||||
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
||||
if(keyCode == KeyEvent.KEYCODE_BACK)
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK)
|
||||
{
|
||||
result.confirm();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
dlg.create();
|
||||
dlg.show();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the client to display a confirm dialog to the user.
|
||||
*
|
||||
*
|
||||
* @param view
|
||||
* @param url
|
||||
* @param message
|
||||
@@ -109,53 +131,53 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
*/
|
||||
@Override
|
||||
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx);
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(this.cordova.getActivity());
|
||||
dlg.setMessage(message);
|
||||
dlg.setTitle("Confirm");
|
||||
dlg.setCancelable(true);
|
||||
dlg.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
result.confirm();
|
||||
}
|
||||
});
|
||||
dlg.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
result.cancel();
|
||||
}
|
||||
});
|
||||
dlg.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
result.confirm();
|
||||
}
|
||||
});
|
||||
dlg.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
result.cancel();
|
||||
}
|
||||
});
|
||||
dlg.setOnCancelListener(
|
||||
new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
result.cancel();
|
||||
new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
result.cancel();
|
||||
}
|
||||
});
|
||||
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
|
||||
//DO NOTHING
|
||||
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
||||
if(keyCode == KeyEvent.KEYCODE_BACK)
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK)
|
||||
{
|
||||
result.cancel();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
dlg.create();
|
||||
dlg.show();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the client to display a prompt dialog to the user.
|
||||
* If the client returns true, WebView will assume that the client will
|
||||
* Tell the client to display a prompt dialog to the user.
|
||||
* If the client returns true, WebView will assume that the client will
|
||||
* handle the prompt dialog and call the appropriate JsPromptResult method.
|
||||
*
|
||||
* Since we are hacking prompts for our own purposes, we should not be using them for
|
||||
*
|
||||
* Since we are hacking prompts for our own purposes, we should not be using them for
|
||||
* this purpose, perhaps we should hack console.log to do this instead!
|
||||
*
|
||||
*
|
||||
* @param view
|
||||
* @param url
|
||||
* @param message
|
||||
@@ -164,14 +186,14 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
*/
|
||||
@Override
|
||||
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
|
||||
|
||||
|
||||
// Security check to make sure any requests are coming from the page initially
|
||||
// loaded in webview and not another loaded in an iframe.
|
||||
boolean reqOk = false;
|
||||
if (url.startsWith("file://") || url.indexOf(this.ctx.baseUrl) == 0 || ctx.isUrlWhiteListed(url)) {
|
||||
if (url.startsWith("file://") || url.indexOf(this.appView.baseUrl) == 0 || this.appView.isUrlWhiteListed(url)) {
|
||||
reqOk = true;
|
||||
}
|
||||
|
||||
|
||||
// Calling PluginManager.exec() to call a native service using
|
||||
// prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true]));
|
||||
if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) {
|
||||
@@ -182,78 +204,72 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
String action = array.getString(1);
|
||||
String callbackId = array.getString(2);
|
||||
boolean async = array.getBoolean(3);
|
||||
String r = ctx.pluginManager.exec(service, action, callbackId, message, async);
|
||||
String r = this.appView.pluginManager.exec(service, action, callbackId, message, async);
|
||||
result.confirm(r);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Polling for JavaScript messages
|
||||
else if (reqOk && defaultValue != null && defaultValue.equals("gap_poll:")) {
|
||||
String r = ctx.callbackServer.getJavascript();
|
||||
String r = this.appView.callbackServer.getJavascript();
|
||||
result.confirm(r);
|
||||
}
|
||||
|
||||
|
||||
// Do NO-OP so older code doesn't display dialog
|
||||
else if (defaultValue != null && defaultValue.equals("gap_init:")) {
|
||||
result.confirm("OK");
|
||||
}
|
||||
|
||||
// Calling into CallbackServer
|
||||
else if (reqOk && defaultValue != null && defaultValue.equals("gap_callbackServer:")) {
|
||||
String r = "";
|
||||
if (message.equals("usePolling")) {
|
||||
r = ""+ ctx.callbackServer.usePolling();
|
||||
r = "" + this.appView.callbackServer.usePolling();
|
||||
}
|
||||
else if (message.equals("restartServer")) {
|
||||
ctx.callbackServer.restartServer();
|
||||
this.appView.callbackServer.restartServer();
|
||||
}
|
||||
else if (message.equals("getPort")) {
|
||||
r = Integer.toString(ctx.callbackServer.getPort());
|
||||
r = Integer.toString(this.appView.callbackServer.getPort());
|
||||
}
|
||||
else if (message.equals("getToken")) {
|
||||
r = ctx.callbackServer.getToken();
|
||||
r = this.appView.callbackServer.getToken();
|
||||
}
|
||||
result.confirm(r);
|
||||
}
|
||||
|
||||
// Cordova JS has initialized, so show webview
|
||||
// (This solves white flash seen when rendering HTML)
|
||||
else if (reqOk && defaultValue != null && defaultValue.equals("gap_init:")) {
|
||||
if (ctx.splashscreen != 0) {
|
||||
ctx.root.setBackgroundResource(0);
|
||||
}
|
||||
ctx.appView.setVisibility(View.VISIBLE);
|
||||
ctx.spinnerStop();
|
||||
result.confirm("OK");
|
||||
}
|
||||
|
||||
// Show dialog
|
||||
else {
|
||||
final JsPromptResult res = result;
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx);
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(this.cordova.getActivity());
|
||||
dlg.setMessage(message);
|
||||
final EditText input = new EditText(this.ctx);
|
||||
final EditText input = new EditText(this.cordova.getActivity());
|
||||
if (defaultValue != null) {
|
||||
input.setText(defaultValue);
|
||||
}
|
||||
dlg.setView(input);
|
||||
dlg.setCancelable(false);
|
||||
dlg.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
String usertext = input.getText().toString();
|
||||
res.confirm(usertext);
|
||||
}
|
||||
});
|
||||
dlg.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
res.cancel();
|
||||
}
|
||||
});
|
||||
dlg.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
String usertext = input.getText().toString();
|
||||
res.confirm(usertext);
|
||||
}
|
||||
});
|
||||
dlg.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
res.cancel();
|
||||
}
|
||||
});
|
||||
dlg.create();
|
||||
dlg.show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle database quota exceeded notification.
|
||||
*
|
||||
@@ -270,7 +286,7 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
{
|
||||
LOG.d(TAG, "DroidGap: onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
|
||||
|
||||
if( estimatedSize < MAX_QUOTA)
|
||||
if (estimatedSize < MAX_QUOTA)
|
||||
{
|
||||
//increase for 1Mb
|
||||
long newQuota = estimatedSize;
|
||||
@@ -286,25 +302,26 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
}
|
||||
|
||||
// console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onConsoleMessage(String message, int lineNumber, String sourceID)
|
||||
{
|
||||
{
|
||||
LOG.d(TAG, "%s: Line %d : %s", sourceID, lineNumber, message);
|
||||
super.onConsoleMessage(message, lineNumber, sourceID);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onConsoleMessage(ConsoleMessage consoleMessage)
|
||||
{
|
||||
if(consoleMessage.message() != null)
|
||||
{
|
||||
if (consoleMessage.message() != null)
|
||||
LOG.d(TAG, consoleMessage.message());
|
||||
return super.onConsoleMessage(consoleMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
|
||||
*
|
||||
* Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
|
||||
*
|
||||
* @param origin
|
||||
* @param callback
|
||||
*/
|
||||
@@ -312,6 +329,4 @@ public class CordovaChromeClient extends WebChromeClient {
|
||||
super.onGeolocationPermissionsShowPrompt(origin, callback);
|
||||
callback.invoke(origin, true, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -38,161 +38,161 @@ public class CordovaLocationListener implements LocationListener {
|
||||
protected LocationManager locationManager;
|
||||
private GeoBroker owner;
|
||||
protected boolean running = false;
|
||||
|
||||
|
||||
public HashMap<String, String> watches = new HashMap<String, String>();
|
||||
private List<String> callbacks = new ArrayList<String>();
|
||||
|
||||
private String TAG = "[Cordova Location Listener]";
|
||||
|
||||
|
||||
public CordovaLocationListener(LocationManager manager, GeoBroker broker, String tag) {
|
||||
this.locationManager = manager;
|
||||
this.owner = broker;
|
||||
this.TAG = tag;
|
||||
this.locationManager = manager;
|
||||
this.owner = broker;
|
||||
this.TAG = tag;
|
||||
}
|
||||
|
||||
|
||||
protected void fail(int code, String message) {
|
||||
for (String callbackId: this.callbacks)
|
||||
{
|
||||
this.owner.fail(code, message, callbackId);
|
||||
this.owner.fail(code, message, callbackId);
|
||||
}
|
||||
this.callbacks.clear();
|
||||
|
||||
|
||||
Iterator it = this.watches.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry pairs = (Map.Entry)it.next();
|
||||
this.owner.fail(code, message, (String)pairs.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void win(Location loc) {
|
||||
for (String callbackId: this.callbacks)
|
||||
for (String callbackId: this.callbacks)
|
||||
{
|
||||
this.owner.win(loc, callbackId);
|
||||
this.owner.win(loc, callbackId);
|
||||
}
|
||||
this.callbacks.clear();
|
||||
|
||||
|
||||
Iterator it = this.watches.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry pairs = (Map.Entry)it.next();
|
||||
this.owner.win(loc, (String)pairs.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Location Listener Methods
|
||||
* Location Listener Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Called when the provider is disabled by the user.
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
public void onProviderDisabled(String provider) {
|
||||
Log.d(TAG, "Location provider '" + provider + "' disabled.");
|
||||
this.fail(POSITION_UNAVAILABLE, "GPS provider disabled.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the provider is enabled by the user.
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
public void onProviderEnabled(String provider) {
|
||||
Log.d(TAG, "Location provider "+ provider + " has been enabled");
|
||||
}
|
||||
/**
|
||||
* Called when the provider is disabled by the user.
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
public void onProviderDisabled(String provider) {
|
||||
Log.d(TAG, "Location provider '" + provider + "' disabled.");
|
||||
this.fail(POSITION_UNAVAILABLE, "GPS provider disabled.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the provider status changes. This method is called when a
|
||||
* provider is unable to fetch a location or if the provider has recently
|
||||
* become available after a period of unavailability.
|
||||
*
|
||||
* @param provider
|
||||
* @param status
|
||||
* @param extras
|
||||
*/
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
Log.d(TAG, "The status of the provider " + provider + " has changed");
|
||||
if (status == 0) {
|
||||
Log.d(TAG, provider + " is OUT OF SERVICE");
|
||||
this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "Provider " + provider + " is out of service.");
|
||||
}
|
||||
else if (status == 1) {
|
||||
Log.d(TAG, provider + " is TEMPORARILY_UNAVAILABLE");
|
||||
}
|
||||
else {
|
||||
Log.d(TAG, provider + " is AVAILABLE");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Called when the provider is enabled by the user.
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
public void onProviderEnabled(String provider) {
|
||||
Log.d(TAG, "Location provider "+ provider + " has been enabled");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the provider status changes. This method is called when a
|
||||
* provider is unable to fetch a location or if the provider has recently
|
||||
* become available after a period of unavailability.
|
||||
*
|
||||
* @param provider
|
||||
* @param status
|
||||
* @param extras
|
||||
*/
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
Log.d(TAG, "The status of the provider " + provider + " has changed");
|
||||
if (status == 0) {
|
||||
Log.d(TAG, provider + " is OUT OF SERVICE");
|
||||
this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "Provider " + provider + " is out of service.");
|
||||
}
|
||||
else if (status == 1) {
|
||||
Log.d(TAG, provider + " is TEMPORARILY_UNAVAILABLE");
|
||||
}
|
||||
else {
|
||||
Log.d(TAG, provider + " is AVAILABLE");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the location has changed.
|
||||
*
|
||||
* @param location
|
||||
*/
|
||||
public void onLocationChanged(Location location) {
|
||||
Log.d(TAG, "The location has been updated!");
|
||||
this.win(location);
|
||||
}
|
||||
|
||||
// PUBLIC
|
||||
|
||||
public int size() {
|
||||
return this.watches.size() + this.callbacks.size();
|
||||
}
|
||||
|
||||
public void addWatch(String timerId, String callbackId) {
|
||||
this.watches.put(timerId, callbackId);
|
||||
if (this.size() == 1) {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
public void addCallback(String callbackId) {
|
||||
this.callbacks.add(callbackId);
|
||||
if (this.size() == 1) {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
public void clearWatch(String timerId) {
|
||||
if (this.watches.containsKey(timerId)) {
|
||||
this.watches.remove(timerId);
|
||||
}
|
||||
if (this.size() == 0) {
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the location has changed.
|
||||
*
|
||||
* @param location
|
||||
*/
|
||||
public void onLocationChanged(Location location) {
|
||||
Log.d(TAG, "The location has been updated!");
|
||||
this.win(location);
|
||||
}
|
||||
|
||||
// PUBLIC
|
||||
|
||||
public int size() {
|
||||
return this.watches.size() + this.callbacks.size();
|
||||
}
|
||||
|
||||
public void addWatch(String timerId, String callbackId) {
|
||||
this.watches.put(timerId, callbackId);
|
||||
if (this.size() == 1) {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
public void addCallback(String callbackId) {
|
||||
this.callbacks.add(callbackId);
|
||||
if (this.size() == 1) {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
public void clearWatch(String timerId) {
|
||||
if (this.watches.containsKey(timerId)) {
|
||||
this.watches.remove(timerId);
|
||||
}
|
||||
if (this.size() == 0) {
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy listener.
|
||||
*/
|
||||
public void destroy() {
|
||||
this.stop();
|
||||
this.stop();
|
||||
}
|
||||
|
||||
// LOCAL
|
||||
|
||||
/**
|
||||
* Start requesting location updates.
|
||||
*
|
||||
* @param interval
|
||||
*/
|
||||
protected void start() {
|
||||
if (!this.running) {
|
||||
if (this.locationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
|
||||
this.running = true;
|
||||
this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 60000, 10, this);
|
||||
} else {
|
||||
this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "Network provider is not available.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop receiving location updates.
|
||||
*/
|
||||
private void stop() {
|
||||
if (this.running) {
|
||||
this.locationManager.removeUpdates(this);
|
||||
this.running = false;
|
||||
}
|
||||
}
|
||||
// LOCAL
|
||||
|
||||
/**
|
||||
* Start requesting location updates.
|
||||
*
|
||||
* @param interval
|
||||
*/
|
||||
protected void start() {
|
||||
if (!this.running) {
|
||||
if (this.locationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
|
||||
this.running = true;
|
||||
this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 60000, 10, this);
|
||||
} else {
|
||||
this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "Network provider is not available.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop receiving location updates.
|
||||
*/
|
||||
private void stop() {
|
||||
if (this.running) {
|
||||
this.locationManager.removeUpdates(this);
|
||||
this.running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
774
framework/src/org/apache/cordova/CordovaWebView.java
Executable file
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Stack;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.cordova.api.CordovaInterface;
|
||||
import org.apache.cordova.api.LOG;
|
||||
import org.apache.cordova.api.PluginManager;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.WindowManager;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebSettings.LayoutAlgorithm;
|
||||
|
||||
public class CordovaWebView extends WebView {
|
||||
|
||||
public static final String TAG = "CordovaWebView";
|
||||
|
||||
/** The whitelist **/
|
||||
private ArrayList<Pattern> whiteList = new ArrayList<Pattern>();
|
||||
private HashMap<String, Boolean> whiteListCache = new HashMap<String, Boolean>();
|
||||
private ArrayList<Integer> keyDownCodes = new ArrayList<Integer>();
|
||||
private ArrayList<Integer> keyUpCodes = new ArrayList<Integer>();
|
||||
|
||||
public PluginManager pluginManager;
|
||||
public CallbackServer callbackServer;
|
||||
|
||||
|
||||
/** Actvities and other important classes **/
|
||||
private CordovaInterface cordova;
|
||||
CordovaWebViewClient viewClient;
|
||||
@SuppressWarnings("unused")
|
||||
private CordovaChromeClient chromeClient;
|
||||
|
||||
//This is for the polyfil history
|
||||
private String url;
|
||||
String baseUrl;
|
||||
private Stack<String> urls = new Stack<String>();
|
||||
|
||||
boolean useBrowserHistory = false;
|
||||
|
||||
// Flag to track that a loadUrl timeout occurred
|
||||
int loadUrlTimeout = 0;
|
||||
|
||||
private boolean bound;
|
||||
|
||||
private boolean volumedownBound;
|
||||
|
||||
private boolean volumeupBound;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public CordovaWebView(Context context) {
|
||||
super(context);
|
||||
if (CordovaInterface.class.isInstance(context))
|
||||
{
|
||||
this.cordova = (CordovaInterface) context;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "Your activity must implement CordovaInterface to work");
|
||||
}
|
||||
this.loadConfiguration();
|
||||
this.setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param context
|
||||
* @param attrs
|
||||
*/
|
||||
public CordovaWebView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
if (CordovaInterface.class.isInstance(context))
|
||||
{
|
||||
this.cordova = (CordovaInterface) context;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "Your activity must implement CordovaInterface to work");
|
||||
}
|
||||
this.setWebChromeClient(new CordovaChromeClient(this.cordova, this));
|
||||
this.setWebViewClient(new CordovaWebViewClient(this.cordova, this));
|
||||
this.loadConfiguration();
|
||||
this.setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param context
|
||||
* @param attrs
|
||||
* @param defStyle
|
||||
*
|
||||
*/
|
||||
public CordovaWebView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
if (CordovaInterface.class.isInstance(context))
|
||||
{
|
||||
this.cordova = (CordovaInterface) context;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "Your activity must implement CordovaInterface to work");
|
||||
}
|
||||
this.setWebChromeClient(new CordovaChromeClient(this.cordova, this));
|
||||
this.setWebViewClient(new CordovaWebViewClient(this.cordova, this));
|
||||
this.loadConfiguration();
|
||||
this.setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param context
|
||||
* @param attrs
|
||||
* @param defStyle
|
||||
* @param privateBrowsing
|
||||
*/
|
||||
public CordovaWebView(Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) {
|
||||
super(context, attrs, defStyle, privateBrowsing);
|
||||
if (CordovaInterface.class.isInstance(context))
|
||||
{
|
||||
this.cordova = (CordovaInterface) context;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(TAG, "Your activity must implement CordovaInterface to work");
|
||||
}
|
||||
this.setWebChromeClient(new CordovaChromeClient(this.cordova));
|
||||
this.setWebViewClient(new CordovaWebViewClient(this.cordova));
|
||||
this.loadConfiguration();
|
||||
this.setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize webview.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private void setup() {
|
||||
|
||||
this.setInitialScale(0);
|
||||
this.setVerticalScrollBarEnabled(false);
|
||||
this.requestFocusFromTouch();
|
||||
|
||||
// Enable JavaScript
|
||||
WebSettings settings = this.getSettings();
|
||||
settings.setJavaScriptEnabled(true);
|
||||
settings.setJavaScriptCanOpenWindowsAutomatically(true);
|
||||
settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
|
||||
|
||||
//Set the nav dump for HTC
|
||||
settings.setNavDump(true);
|
||||
|
||||
// Enable database
|
||||
settings.setDatabaseEnabled(true);
|
||||
String databasePath = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
|
||||
settings.setDatabasePath(databasePath);
|
||||
|
||||
// Enable DOM storage
|
||||
settings.setDomStorageEnabled(true);
|
||||
|
||||
// Enable built-in geolocation
|
||||
settings.setGeolocationEnabled(true);
|
||||
|
||||
//Start up the plugin manager
|
||||
try {
|
||||
this.pluginManager = new PluginManager(this, this.cordova);
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the WebViewClient.
|
||||
*
|
||||
* @param client
|
||||
*/
|
||||
public void setWebViewClient(CordovaWebViewClient client) {
|
||||
this.viewClient = client;
|
||||
super.setWebViewClient(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the WebChromeClient.
|
||||
*
|
||||
* @param client
|
||||
*/
|
||||
public void setWebChromeClient(CordovaChromeClient client) {
|
||||
this.chromeClient = client;
|
||||
super.setWebChromeClient(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add entry to approved list of URLs (whitelist)
|
||||
*
|
||||
* @param origin URL regular expression to allow
|
||||
* @param subdomains T=include all subdomains under origin
|
||||
*/
|
||||
public void addWhiteListEntry(String origin, boolean subdomains) {
|
||||
try {
|
||||
// Unlimited access to network resources
|
||||
if (origin.compareTo("*") == 0) {
|
||||
LOG.d(TAG, "Unlimited access to network resources");
|
||||
this.whiteList.add(Pattern.compile(".*"));
|
||||
} else { // specific access
|
||||
// check if subdomains should be included
|
||||
// TODO: we should not add more domains if * has already been added
|
||||
if (subdomains) {
|
||||
// XXX making it stupid friendly for people who forget to include protocol/SSL
|
||||
if (origin.startsWith("http")) {
|
||||
this.whiteList.add(Pattern.compile(origin.replaceFirst("https?://", "^https?://(.*\\.)?")));
|
||||
} else {
|
||||
this.whiteList.add(Pattern.compile("^https?://(.*\\.)?" + origin));
|
||||
}
|
||||
LOG.d(TAG, "Origin to allow with subdomains: %s", origin);
|
||||
} else {
|
||||
// XXX making it stupid friendly for people who forget to include protocol/SSL
|
||||
if (origin.startsWith("http")) {
|
||||
this.whiteList.add(Pattern.compile(origin.replaceFirst("https?://", "^https?://")));
|
||||
} else {
|
||||
this.whiteList.add(Pattern.compile("^https?://" + origin));
|
||||
}
|
||||
LOG.d(TAG, "Origin to allow: %s", origin);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.d(TAG, "Failed to add origin %s", origin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if URL is in approved list of URLs to load.
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public boolean isUrlWhiteListed(String url) {
|
||||
|
||||
// Check to see if we have matched url previously
|
||||
if (this.whiteListCache.get(url) != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Look for match in white list
|
||||
Iterator<Pattern> pit = this.whiteList.iterator();
|
||||
while (pit.hasNext()) {
|
||||
Pattern p = pit.next();
|
||||
Matcher m = p.matcher(url);
|
||||
|
||||
// If match found, then cache it to speed up subsequent comparisons
|
||||
if (m.find()) {
|
||||
this.whiteListCache.put(url, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the url into the webview.
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
@Override
|
||||
public void loadUrl(String url) {
|
||||
if (url.equals("about:blank") || url.startsWith("javascript:")) {
|
||||
this.loadUrlNow(url);
|
||||
}
|
||||
else {
|
||||
|
||||
String initUrl = this.getProperty("url", null);
|
||||
|
||||
// If first page of app, then set URL to load to be the one passed in
|
||||
if (initUrl == null || (this.urls.size() > 0)) {
|
||||
this.loadUrlIntoView(url);
|
||||
}
|
||||
// Otherwise use the URL specified in the activity's extras bundle
|
||||
else {
|
||||
this.loadUrlIntoView(initUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the url into the webview after waiting for period of time.
|
||||
* This is used to display the splashscreen for certain amount of time.
|
||||
*
|
||||
* @param url
|
||||
* @param time The number of ms to wait before loading webview
|
||||
*/
|
||||
public void loadUrl(final String url, int time) {
|
||||
String initUrl = this.getProperty("url", null);
|
||||
|
||||
// If first page of app, then set URL to load to be the one passed in
|
||||
if (initUrl == null || (this.urls.size() > 0)) {
|
||||
this.loadUrlIntoView(url, time);
|
||||
}
|
||||
// Otherwise use the URL specified in the activity's extras bundle
|
||||
else {
|
||||
this.loadUrlIntoView(initUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the url into the webview.
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
public void loadUrlIntoView(final String url) {
|
||||
LOG.d(TAG, ">>> loadUrl(" + url + ")");
|
||||
|
||||
this.url = url;
|
||||
if (this.baseUrl == null) {
|
||||
int i = url.lastIndexOf('/');
|
||||
if (i > 0) {
|
||||
this.baseUrl = url.substring(0, i + 1);
|
||||
}
|
||||
else {
|
||||
this.baseUrl = this.url + "/";
|
||||
}
|
||||
|
||||
this.pluginManager.init();
|
||||
|
||||
if (!this.useBrowserHistory) {
|
||||
this.urls.push(url);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a timeout timer for loadUrl
|
||||
final CordovaWebView me = this;
|
||||
final int currentLoadUrlTimeout = me.loadUrlTimeout;
|
||||
final int loadUrlTimeoutValue = Integer.parseInt(this.getProperty("loadUrlTimeoutValue", "20000"));
|
||||
|
||||
// Timeout error method
|
||||
final Runnable loadError = new Runnable() {
|
||||
public void run() {
|
||||
me.stopLoading();
|
||||
LOG.e(TAG, "CordovaWebView: TIMEOUT ERROR!");
|
||||
if (viewClient != null) {
|
||||
viewClient.onReceivedError(me, -6, "The connection to the server was unsuccessful.", url);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Timeout timer method
|
||||
final Runnable timeoutCheck = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
synchronized (this) {
|
||||
wait(loadUrlTimeoutValue);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// If timeout, then stop loading and handle error
|
||||
if (me.loadUrlTimeout == currentLoadUrlTimeout) {
|
||||
me.cordova.getActivity().runOnUiThread(loadError);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Load url
|
||||
this.cordova.getActivity().runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
Thread thread = new Thread(timeoutCheck);
|
||||
thread.start();
|
||||
me.loadUrlNow(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load URL in webview.
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
private void loadUrlNow(String url) {
|
||||
LOG.d(TAG, ">>> loadUrlNow()");
|
||||
super.loadUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the url into the webview after waiting for period of time.
|
||||
* This is used to display the splashscreen for certain amount of time.
|
||||
*
|
||||
* @param url
|
||||
* @param time The number of ms to wait before loading webview
|
||||
*/
|
||||
public void loadUrlIntoView(final String url, final int time) {
|
||||
|
||||
// If not first page of app, then load immediately
|
||||
// Add support for browser history if we use it.
|
||||
if ((url.startsWith("javascript:")) || this.urls.size() > 0 || this.canGoBack()) {
|
||||
}
|
||||
|
||||
// If first page, then show splashscreen
|
||||
else {
|
||||
|
||||
LOG.d(TAG, "DroidGap.loadUrl(%s, %d)", url, time);
|
||||
|
||||
// Send message to show splashscreen now if desired
|
||||
this.postMessage("splashscreen", "show");
|
||||
}
|
||||
|
||||
// Load url
|
||||
this.loadUrlIntoView(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send JavaScript statement back to JavaScript.
|
||||
* (This is a convenience method)
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
public void sendJavascript(String statement) {
|
||||
if (this.callbackServer != null) {
|
||||
this.callbackServer.sendJavascript(statement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to all plugins.
|
||||
*
|
||||
* @param id The message id
|
||||
* @param data The message data
|
||||
*/
|
||||
public void postMessage(String id, Object data) {
|
||||
if (this.pluginManager != null) {
|
||||
this.pluginManager.postMessage(id, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the top url on the stack without removing it from
|
||||
* the stack.
|
||||
*/
|
||||
public String peekAtUrlStack() {
|
||||
if (this.urls.size() > 0) {
|
||||
return this.urls.peek();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a url to the stack
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
public void pushUrl(String url) {
|
||||
this.urls.push(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to previous page in history. (We manage our own history)
|
||||
*
|
||||
* @return true if we went back, false if we are already at top
|
||||
*/
|
||||
public boolean backHistory() {
|
||||
|
||||
// Check webview first to see if there is a history
|
||||
// This is needed to support curPage#diffLink, since they are added to appView's history, but not our history url array (JQMobile behavior)
|
||||
if (super.canGoBack()) {
|
||||
super.goBack();
|
||||
return true;
|
||||
}
|
||||
|
||||
// If our managed history has prev url
|
||||
if (this.urls.size() > 1) {
|
||||
this.urls.pop(); // Pop current url
|
||||
String url = this.urls.pop(); // Pop prev url that we want to load, since it will be added back by loadUrl()
|
||||
this.loadUrl(url);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is a history item.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean canGoBack() {
|
||||
if (super.canGoBack()) {
|
||||
return true;
|
||||
}
|
||||
if (this.urls.size() > 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the specified URL in the Cordova webview or a new browser instance.
|
||||
*
|
||||
* NOTE: If openExternal is false, only URLs listed in whitelist can be loaded.
|
||||
*
|
||||
* @param url The url to load.
|
||||
* @param openExternal Load url in browser instead of Cordova webview.
|
||||
* @param clearHistory Clear the history stack, so new page becomes top of history
|
||||
* @param params DroidGap parameters for new app
|
||||
*/
|
||||
public void showWebPage(String url, boolean openExternal, boolean clearHistory, HashMap<String, Object> params) {
|
||||
LOG.d(TAG, "showWebPage(%s, %b, %b, HashMap", url, openExternal, clearHistory);
|
||||
|
||||
// If clearing history
|
||||
if (clearHistory) {
|
||||
this.clearHistory();
|
||||
}
|
||||
|
||||
// If loading into our webview
|
||||
if (!openExternal) {
|
||||
|
||||
// Make sure url is in whitelist
|
||||
if (url.startsWith("file://") || url.indexOf(this.baseUrl) == 0 || isUrlWhiteListed(url)) {
|
||||
// TODO: What about params?
|
||||
|
||||
// Clear out current url from history, since it will be replacing it
|
||||
if (clearHistory) {
|
||||
this.urls.clear();
|
||||
}
|
||||
|
||||
// Load new URL
|
||||
this.loadUrl(url);
|
||||
}
|
||||
// Load in default viewer if not
|
||||
else {
|
||||
LOG.w(TAG, "showWebPage: Cannot load URL into webview since it is not in white list. Loading into browser instead. (URL=" + url + ")");
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(url));
|
||||
cordova.getActivity().startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error loading url " + url, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load in default view intent
|
||||
else {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(url));
|
||||
cordova.getActivity().startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error loading url " + url, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Cordova configuration from res/xml/cordova.xml.
|
||||
* Approved list of URLs that can be loaded into DroidGap
|
||||
* <access origin="http://server regexp" subdomains="true" />
|
||||
* Log level: ERROR, WARN, INFO, DEBUG, VERBOSE (default=ERROR)
|
||||
* <log level="DEBUG" />
|
||||
*/
|
||||
private void loadConfiguration() {
|
||||
int id = getResources().getIdentifier("cordova", "xml", this.cordova.getActivity().getPackageName());
|
||||
if (id == 0) {
|
||||
LOG.i("CordovaLog", "cordova.xml missing. Ignoring...");
|
||||
return;
|
||||
}
|
||||
XmlResourceParser xml = getResources().getXml(id);
|
||||
int eventType = -1;
|
||||
while (eventType != XmlResourceParser.END_DOCUMENT) {
|
||||
if (eventType == XmlResourceParser.START_TAG) {
|
||||
String strNode = xml.getName();
|
||||
if (strNode.equals("access")) {
|
||||
String origin = xml.getAttributeValue(null, "origin");
|
||||
String subdomains = xml.getAttributeValue(null, "subdomains");
|
||||
if (origin != null) {
|
||||
this.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0));
|
||||
}
|
||||
}
|
||||
else if (strNode.equals("log")) {
|
||||
String level = xml.getAttributeValue(null, "level");
|
||||
LOG.i("CordovaLog", "Found log level %s", level);
|
||||
if (level != null) {
|
||||
LOG.setLogLevel(level);
|
||||
}
|
||||
}
|
||||
else if (strNode.equals("preference")) {
|
||||
String name = xml.getAttributeValue(null, "name");
|
||||
String value = xml.getAttributeValue(null, "value");
|
||||
|
||||
LOG.i("CordovaLog", "Found preference for %s=%s", name, value);
|
||||
|
||||
// Save preferences in Intent
|
||||
this.cordova.getActivity().getIntent().putExtra(name, value);
|
||||
}
|
||||
}
|
||||
try {
|
||||
eventType = xml.next();
|
||||
} catch (XmlPullParserException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// Init preferences
|
||||
if ("true".equals(this.getProperty("useBrowserHistory", "true"))) {
|
||||
this.useBrowserHistory = true;
|
||||
}
|
||||
else {
|
||||
this.useBrowserHistory = false;
|
||||
}
|
||||
|
||||
if ("true".equals(this.getProperty("fullscreen", "false"))) {
|
||||
this.cordova.getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
|
||||
this.cordova.getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string property for activity.
|
||||
*
|
||||
* @param name
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
public String getProperty(String name, String defaultValue) {
|
||||
Bundle bundle = this.cordova.getActivity().getIntent().getExtras();
|
||||
if (bundle == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
Object p = bundle.get(name);
|
||||
if (p == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return p.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* onKeyDown
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event)
|
||||
{
|
||||
if(keyDownCodes.contains(keyCode))
|
||||
{
|
||||
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
|
||||
// only override default behaviour is event bound
|
||||
LOG.d(TAG, "Down Key Hit");
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');");
|
||||
return true;
|
||||
}
|
||||
// If volumeup key
|
||||
else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
|
||||
LOG.d(TAG, "Up Key Hit");
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Do some other stuff!
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event)
|
||||
{
|
||||
|
||||
Log.d(TAG, "KeyDown has been triggered on the view");
|
||||
|
||||
// If back key
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
// If back key is bound, then send event to JavaScript
|
||||
if (this.bound) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('backbutton');");
|
||||
return true;
|
||||
} else {
|
||||
// If not bound
|
||||
// Go to previous page in webview if it is possible to go back
|
||||
if (this.backHistory()) {
|
||||
return true;
|
||||
}
|
||||
// If not, then invoke default behaviour
|
||||
else {
|
||||
//this.activityState = ACTIVITY_EXITING;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Legacy
|
||||
else if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('menubutton');");
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
// If search key
|
||||
else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
|
||||
this.loadUrl("javascript:cordova.fireDocumentEvent('searchbutton');");
|
||||
return true;
|
||||
}
|
||||
else if(keyUpCodes.contains(keyCode))
|
||||
{
|
||||
//What the hell should this do?
|
||||
}
|
||||
|
||||
|
||||
Log.d(TAG, "KeyUp has been triggered on the view");
|
||||
return false;
|
||||
}
|
||||
|
||||
public void bindButton(boolean override)
|
||||
{
|
||||
this.bound = override;
|
||||
}
|
||||
|
||||
public void bindButton(String button, boolean override) {
|
||||
// TODO Auto-generated method stub
|
||||
if (button.compareTo("volumeup")==0) {
|
||||
keyDownCodes.add(KeyEvent.KEYCODE_VOLUME_UP);
|
||||
}
|
||||
else if (button.compareTo("volumedown")==0) {
|
||||
keyDownCodes.add(KeyEvent.KEYCODE_VOLUME_DOWN);
|
||||
}
|
||||
}
|
||||
|
||||
public void bindButton(int keyCode, boolean keyDown, boolean override) {
|
||||
if(keyDown)
|
||||
{
|
||||
keyDownCodes.add(keyCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyUpCodes.add(keyCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,19 +18,29 @@
|
||||
*/
|
||||
package org.apache.cordova;
|
||||
|
||||
import org.apache.cordova.api.LOG;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.apache.cordova.api.CordovaInterface;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.cordova.api.LOG;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.net.http.SslError;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.webkit.HttpAuthHandler;
|
||||
import android.webkit.SslErrorHandler;
|
||||
import android.webkit.WebResourceResponse;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
@@ -38,43 +48,67 @@ import android.webkit.WebViewClient;
|
||||
* This class is the WebViewClient that implements callbacks for our web view.
|
||||
*/
|
||||
public class CordovaWebViewClient extends WebViewClient {
|
||||
|
||||
|
||||
private static final String TAG = "Cordova";
|
||||
DroidGap ctx;
|
||||
CordovaInterface cordova;
|
||||
CordovaWebView appView;
|
||||
private boolean doClearHistory = false;
|
||||
|
||||
/** The authorization tokens. */
|
||||
private Hashtable<String, AuthenticationToken> authenticationTokens = new Hashtable<String, AuthenticationToken>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param cordova
|
||||
*/
|
||||
public CordovaWebViewClient(CordovaInterface cordova) {
|
||||
this.cordova = cordova;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ctx
|
||||
* @param cordova
|
||||
* @param view
|
||||
*/
|
||||
public CordovaWebViewClient(DroidGap ctx) {
|
||||
this.ctx = ctx;
|
||||
public CordovaWebViewClient(CordovaInterface cordova, CordovaWebView view) {
|
||||
this.cordova = cordova;
|
||||
this.appView = view;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Give the host application a chance to take over the control when a new url
|
||||
* is about to be loaded in the current WebView.
|
||||
* Constructor.
|
||||
*
|
||||
* @param view
|
||||
*/
|
||||
public void setWebView(CordovaWebView view) {
|
||||
this.appView = view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the host application a chance to take over the control when a new url
|
||||
* is about to be loaded in the current WebView.
|
||||
*
|
||||
* @param view The WebView that is initiating the callback.
|
||||
* @param url The url to be loaded.
|
||||
* @return true to override, false for default behavior
|
||||
*/
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
|
||||
|
||||
// First give any plugins the chance to handle the url themselves
|
||||
if ((this.ctx.pluginManager != null) && this.ctx.pluginManager.onOverrideUrlLoading(url)) {
|
||||
if ((this.appView.pluginManager != null) && this.appView.pluginManager.onOverrideUrlLoading(url)) {
|
||||
}
|
||||
|
||||
|
||||
// If dialing phone (tel:5551212)
|
||||
else if (url.startsWith(WebView.SCHEME_TEL)) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_DIAL);
|
||||
intent.setData(Uri.parse(url));
|
||||
ctx.startActivity(intent);
|
||||
this.cordova.getActivity().startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error dialing "+url+": "+ e.toString());
|
||||
LOG.e(TAG, "Error dialing " + url + ": " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,9 +117,9 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(url));
|
||||
ctx.startActivity(intent);
|
||||
this.cordova.getActivity().startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error showing map "+url+": "+ e.toString());
|
||||
LOG.e(TAG, "Error showing map " + url + ": " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,9 +128,9 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(url));
|
||||
ctx.startActivity(intent);
|
||||
this.cordova.getActivity().startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error sending email "+url+": "+ e.toString());
|
||||
LOG.e(TAG, "Error sending email " + url + ": " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,12 +157,12 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
intent.setData(Uri.parse("sms:"+address));
|
||||
intent.setData(Uri.parse("sms:" + address));
|
||||
intent.putExtra("address", address);
|
||||
intent.setType("vnd.android-dir/mms-sms");
|
||||
ctx.startActivity(intent);
|
||||
this.cordova.getActivity().startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error sending sms "+url+":"+ e.toString());
|
||||
LOG.e(TAG, "Error sending sms " + url + ":" + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,8 +171,12 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
|
||||
// If our app or file:, then load into a new Cordova webview container by starting a new instance of our activity.
|
||||
// Our app continues to run. When BACK is pressed, our app is redisplayed.
|
||||
if (url.startsWith("file://") || url.indexOf(this.ctx.baseUrl) == 0 || ctx.isUrlWhiteListed(url)) {
|
||||
this.ctx.loadUrl(url);
|
||||
if (url.startsWith("file://") || url.indexOf(this.appView.baseUrl) == 0 || this.appView.isUrlWhiteListed(url)) {
|
||||
//This will fix iFrames
|
||||
if (appView.useBrowserHistory)
|
||||
return false;
|
||||
else
|
||||
this.appView.loadUrl(url);
|
||||
}
|
||||
|
||||
// If not our application, let default viewer handle
|
||||
@@ -146,62 +184,81 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(url));
|
||||
ctx.startActivity(intent);
|
||||
this.cordova.getActivity().startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error loading url "+url, e);
|
||||
LOG.e(TAG, "Error loading url " + url, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* On received http auth request.
|
||||
* The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination
|
||||
*
|
||||
* The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination
|
||||
*
|
||||
* @param view
|
||||
* the view
|
||||
* @param handler
|
||||
* the handler
|
||||
* @param host
|
||||
* the host
|
||||
* @param realm
|
||||
* the realm
|
||||
*/
|
||||
@Override
|
||||
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host,
|
||||
String realm) {
|
||||
|
||||
// get the authentication token
|
||||
AuthenticationToken token = ctx.getAuthenticationToken(host,realm);
|
||||
|
||||
if(token != null) {
|
||||
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
|
||||
|
||||
// Get the authentication token
|
||||
AuthenticationToken token = this.getAuthenticationToken(host, realm);
|
||||
if (token != null) {
|
||||
handler.proceed(token.getUserName(), token.getPassword());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify the host application that a page has started loading.
|
||||
* This method is called once for each main frame load so a page with iframes or framesets will call onPageStarted
|
||||
* one time for the main frame. This also means that onPageStarted will not be called when the contents of an
|
||||
* embedded frame changes, i.e. clicking a link whose target is an iframe.
|
||||
*
|
||||
* @param view The webview initiating the callback.
|
||||
* @param url The url of the page.
|
||||
*/
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
// Clear history so history.back() doesn't do anything.
|
||||
// Clear history so history.back() doesn't do anything.
|
||||
// So we can reinit() native side CallbackServer & PluginManager.
|
||||
view.clearHistory();
|
||||
this.doClearHistory = true;
|
||||
if (!this.appView.useBrowserHistory) {
|
||||
view.clearHistory();
|
||||
this.doClearHistory = true;
|
||||
}
|
||||
|
||||
// Create callback server and plugin manager
|
||||
if (this.appView.callbackServer == null) {
|
||||
this.appView.callbackServer = new CallbackServer();
|
||||
this.appView.callbackServer.init(url);
|
||||
}
|
||||
else {
|
||||
this.appView.callbackServer.reinit(url);
|
||||
}
|
||||
|
||||
// Broadcast message that page has loaded
|
||||
this.appView.postMessage("onPageStarted", url);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify the host application that a page has finished loading.
|
||||
* This method is called only for main frame. When onPageFinished() is called, the rendering picture may not be updated yet.
|
||||
*
|
||||
*
|
||||
* @param view The webview initiating the callback.
|
||||
* @param url The url of the page.
|
||||
*/
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
LOG.d(TAG, "onPageFinished(" + url + ")");
|
||||
|
||||
/**
|
||||
* Because of a timing issue we need to clear this history in onPageFinished as well as
|
||||
* onPageStarted. However we only want to do this if the doClearHistory boolean is set to
|
||||
* Because of a timing issue we need to clear this history in onPageFinished as well as
|
||||
* onPageStarted. However we only want to do this if the doClearHistory boolean is set to
|
||||
* true. You see when you load a url with a # in it which is common in jQuery applications
|
||||
* onPageStared is not called. Clearing the history at that point would break jQuery apps.
|
||||
*/
|
||||
@@ -211,29 +268,28 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
}
|
||||
|
||||
// Clear timeout flag
|
||||
this.ctx.loadUrlTimeout++;
|
||||
this.appView.loadUrlTimeout++;
|
||||
|
||||
// Try firing the onNativeReady event in JS. If it fails because the JS is
|
||||
// not loaded yet then just set a flag so that the onNativeReady can be fired
|
||||
// from the JS side when the JS gets to that code.
|
||||
if (!url.equals("about:blank")) {
|
||||
ctx.appView.loadUrl("javascript:try{ cordova.require('cordova/channel').onNativeReady.fire();}catch(e){_nativeReady = true;}");
|
||||
this.ctx.postMessage("onNativeReady", null);
|
||||
this.appView.loadUrl("javascript:try{ cordova.require('cordova/channel').onNativeReady.fire();}catch(e){_nativeReady = true;}");
|
||||
this.appView.postMessage("onNativeReady", null);
|
||||
}
|
||||
|
||||
// Broadcast message that page has loaded
|
||||
this.appView.postMessage("onPageFinished", url);
|
||||
|
||||
// Make app visible after 2 sec in case there was a JS error and Cordova JS never initialized correctly
|
||||
if (ctx.appView.getVisibility() == View.INVISIBLE) {
|
||||
if (this.appView.getVisibility() == View.INVISIBLE) {
|
||||
Thread t = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
ctx.runOnUiThread(new Runnable() {
|
||||
cordova.getActivity().runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if (ctx.splashscreen != 0) {
|
||||
ctx.root.setBackgroundResource(0);
|
||||
}
|
||||
ctx.appView.setVisibility(View.VISIBLE);
|
||||
ctx.spinnerStop();
|
||||
appView.postMessage("spinner", "stop");
|
||||
}
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
@@ -243,43 +299,59 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
t.start();
|
||||
}
|
||||
|
||||
|
||||
// Shutdown if blank loaded
|
||||
if (url.equals("about:blank")) {
|
||||
if (this.ctx.callbackServer != null) {
|
||||
this.ctx.callbackServer.destroy();
|
||||
if (this.appView.callbackServer != null) {
|
||||
this.appView.callbackServer.destroy();
|
||||
}
|
||||
this.ctx.endActivity();
|
||||
appView.postMessage("exit", null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).
|
||||
* Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).
|
||||
* The errorCode parameter corresponds to one of the ERROR_* constants.
|
||||
*
|
||||
* @param view The WebView that is initiating the callback.
|
||||
* @param errorCode The error code corresponding to an ERROR_* value.
|
||||
* @param description A String describing the error.
|
||||
* @param failingUrl The url that failed to load.
|
||||
* @param failingUrl The url that failed to load.
|
||||
*/
|
||||
@Override
|
||||
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
|
||||
LOG.d(TAG, "DroidGap: GapViewClient.onReceivedError: Error code=%s Description=%s URL=%s", errorCode, description, failingUrl);
|
||||
LOG.d(TAG, "CordovaWebViewClient.onReceivedError: Error code=%s Description=%s URL=%s", errorCode, description, failingUrl);
|
||||
|
||||
// Clear timeout flag
|
||||
this.ctx.loadUrlTimeout++;
|
||||
|
||||
// Stop "app loading" spinner if showing
|
||||
this.ctx.spinnerStop();
|
||||
this.appView.loadUrlTimeout++;
|
||||
|
||||
// Handle error
|
||||
this.ctx.onReceivedError(errorCode, description, failingUrl);
|
||||
JSONObject data = new JSONObject();
|
||||
try {
|
||||
data.put("errorCode", errorCode);
|
||||
data.put("description", description);
|
||||
data.put("url", failingUrl);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.appView.postMessage("onReceivedError", data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify the host application that an SSL error occurred while loading a resource.
|
||||
* The host application must call either handler.cancel() or handler.proceed().
|
||||
* Note that the decision may be retained for use in response to future SSL errors.
|
||||
* The default behavior is to cancel the load.
|
||||
*
|
||||
* @param view The WebView that is initiating the callback.
|
||||
* @param handler An SslErrorHandler object that will handle the user's response.
|
||||
* @param error The SSL error object.
|
||||
*/
|
||||
@Override
|
||||
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
|
||||
|
||||
final String packageName = this.ctx.getPackageName();
|
||||
final PackageManager pm = this.ctx.getPackageManager();
|
||||
|
||||
final String packageName = this.cordova.getActivity().getPackageName();
|
||||
final PackageManager pm = this.cordova.getActivity().getPackageManager();
|
||||
|
||||
ApplicationInfo appInfo;
|
||||
try {
|
||||
appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
|
||||
@@ -289,7 +361,7 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
return;
|
||||
} else {
|
||||
// debug = false
|
||||
super.onReceivedSslError(view, handler, error);
|
||||
super.onReceivedSslError(view, handler, error);
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
// When it doubt, lock it out!
|
||||
@@ -297,14 +369,133 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the host application to update its visited links database.
|
||||
*
|
||||
* @param view The WebView that is initiating the callback.
|
||||
* @param url The url being visited.
|
||||
* @param isReload True if this url is being reloaded.
|
||||
*/
|
||||
@Override
|
||||
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
|
||||
/*
|
||||
/*
|
||||
* If you do a document.location.href the url does not get pushed on the stack
|
||||
* so we do a check here to see if the url should be pushed.
|
||||
*/
|
||||
if (!this.ctx.peekAtUrlStack().equals(url)) {
|
||||
this.ctx.pushUrl(url);
|
||||
if (!this.appView.peekAtUrlStack().equals(url)) {
|
||||
this.appView.pushUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the authentication token.
|
||||
*
|
||||
* @param authenticationToken
|
||||
* @param host
|
||||
* @param realm
|
||||
*/
|
||||
public void setAuthenticationToken(AuthenticationToken authenticationToken, String host, String realm) {
|
||||
if (host == null) {
|
||||
host = "";
|
||||
}
|
||||
if (realm == null) {
|
||||
realm = "";
|
||||
}
|
||||
this.authenticationTokens.put(host.concat(realm), authenticationToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the authentication token.
|
||||
*
|
||||
* @param host
|
||||
* @param realm
|
||||
*
|
||||
* @return the authentication token or null if did not exist
|
||||
*/
|
||||
public AuthenticationToken removeAuthenticationToken(String host, String realm) {
|
||||
return this.authenticationTokens.remove(host.concat(realm));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the authentication token.
|
||||
*
|
||||
* In order it tries:
|
||||
* 1- host + realm
|
||||
* 2- host
|
||||
* 3- realm
|
||||
* 4- no host, no realm
|
||||
*
|
||||
* @param host
|
||||
* @param realm
|
||||
*
|
||||
* @return the authentication token
|
||||
*/
|
||||
public AuthenticationToken getAuthenticationToken(String host, String realm) {
|
||||
AuthenticationToken token = null;
|
||||
token = this.authenticationTokens.get(host.concat(realm));
|
||||
|
||||
if (token == null) {
|
||||
// try with just the host
|
||||
token = this.authenticationTokens.get(host);
|
||||
|
||||
// Try the realm
|
||||
if (token == null) {
|
||||
token = this.authenticationTokens.get(realm);
|
||||
}
|
||||
|
||||
// if no host found, just query for default
|
||||
if (token == null) {
|
||||
token = this.authenticationTokens.get("");
|
||||
}
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all authentication tokens.
|
||||
*/
|
||||
public void clearAuthenticationTokens() {
|
||||
this.authenticationTokens.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
|
||||
if(url.contains("?") || url.contains("#")){
|
||||
return generateWebResourceResponse(url);
|
||||
} else {
|
||||
return super.shouldInterceptRequest(view, url);
|
||||
}
|
||||
}
|
||||
|
||||
private WebResourceResponse generateWebResourceResponse(String url) {
|
||||
final String ANDROID_ASSET = "file:///android_asset/";
|
||||
if (url.startsWith(ANDROID_ASSET)) {
|
||||
String niceUrl = url;
|
||||
niceUrl = url.replaceFirst(ANDROID_ASSET, "");
|
||||
if(niceUrl.contains("?")){
|
||||
niceUrl = niceUrl.split("\\?")[0];
|
||||
}
|
||||
else if(niceUrl.contains("#"))
|
||||
{
|
||||
niceUrl = niceUrl.split("#")[0];
|
||||
}
|
||||
|
||||
String mimetype = null;
|
||||
if(niceUrl.endsWith(".html")){
|
||||
mimetype = "text/html";
|
||||
}
|
||||
|
||||
try {
|
||||
AssetManager assets = cordova.getActivity().getAssets();
|
||||
Uri uri = Uri.parse(niceUrl);
|
||||
InputStream stream = assets.open(uri.getPath(), AssetManager.ACCESS_STREAMING);
|
||||
WebResourceResponse response = new WebResourceResponse(mimetype, "UTF-8", stream);
|
||||
return response;
|
||||
} catch (IOException e) {
|
||||
LOG.e("generateWebResourceResponse", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,10 @@ import android.telephony.TelephonyManager;
|
||||
public class Device extends Plugin {
|
||||
public static final String TAG = "Device";
|
||||
|
||||
public static String cordovaVersion = "1.8.0"; // Cordova version
|
||||
public static String cordovaVersion = "1.9.0rc1"; // Cordova version
|
||||
public static String platform = "Android"; // Device OS
|
||||
public static String uuid; // Device UUID
|
||||
|
||||
|
||||
BroadcastReceiver telephonyReceiver = null;
|
||||
|
||||
/**
|
||||
@@ -49,22 +49,22 @@ public class Device extends Plugin {
|
||||
*/
|
||||
public Device() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*
|
||||
* @param cordova The context of the main Activity.
|
||||
*/
|
||||
public void setContext(CordovaInterface ctx) {
|
||||
super.setContext(ctx);
|
||||
public void setContext(CordovaInterface cordova) {
|
||||
super.setContext(cordova);
|
||||
Device.uuid = getUuid();
|
||||
this.initTelephonyReceiver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
@@ -72,8 +72,8 @@ public class Device extends Plugin {
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("getDeviceInfo")) {
|
||||
JSONObject r = new JSONObject();
|
||||
@@ -95,7 +95,7 @@ public class Device extends Plugin {
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
@@ -105,115 +105,114 @@ public class Device extends Plugin {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unregister receiver.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
this.ctx.unregisterReceiver(this.telephonyReceiver);
|
||||
this.cordova.getActivity().unregisterReceiver(this.telephonyReceiver);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Listen for telephony events: RINGING, OFFHOOK and IDLE
|
||||
* Send these events to all plugins using
|
||||
* DroidGap.onMessage("telephone", "ringing" | "offhook" | "idle")
|
||||
*/
|
||||
private void initTelephonyReceiver() {
|
||||
IntentFilter intentFilter = new IntentFilter() ;
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
|
||||
final CordovaInterface myctx = this.ctx;
|
||||
//final CordovaInterface mycordova = this.cordova;
|
||||
this.telephonyReceiver = new BroadcastReceiver() {
|
||||
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
||||
|
||||
// If state has changed
|
||||
if ((intent != null) && intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
|
||||
if (intent.hasExtra(TelephonyManager.EXTRA_STATE)) {
|
||||
String extraData = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
|
||||
if (extraData.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
|
||||
LOG.i(TAG, "Telephone RINGING");
|
||||
myctx.postMessage("telephone", "ringing");
|
||||
webView.postMessage("telephone", "ringing");
|
||||
}
|
||||
else if (extraData.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
|
||||
LOG.i(TAG, "Telephone OFFHOOK");
|
||||
myctx.postMessage("telephone", "offhook");
|
||||
webView.postMessage("telephone", "offhook");
|
||||
}
|
||||
else if (extraData.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
|
||||
LOG.i(TAG, "Telephone IDLE");
|
||||
myctx.postMessage("telephone", "idle");
|
||||
webView.postMessage("telephone", "idle");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Register the receiver
|
||||
this.ctx.registerReceiver(this.telephonyReceiver, intentFilter);
|
||||
this.cordova.getActivity().registerReceiver(this.telephonyReceiver, intentFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the OS name.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getPlatform() {
|
||||
return Device.platform;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the device's Universally Unique Identifier (UUID).
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getUuid() {
|
||||
String uuid = Settings.Secure.getString(this.ctx.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
|
||||
public String getUuid() {
|
||||
String uuid = Settings.Secure.getString(this.cordova.getActivity().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Cordova version.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getCordovaVersion() {
|
||||
return Device.cordovaVersion;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
String model = android.os.Build.MODEL;
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
public String getProductName() {
|
||||
String productname = android.os.Build.PRODUCT;
|
||||
return productname;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the OS version.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getOSVersion() {
|
||||
String osversion = android.os.Build.VERSION.RELEASE;
|
||||
return osversion;
|
||||
}
|
||||
|
||||
|
||||
public String getSDKVersion() {
|
||||
@SuppressWarnings("deprecation")
|
||||
String sdkversion = android.os.Build.VERSION.SDK;
|
||||
return sdkversion;
|
||||
}
|
||||
|
||||
|
||||
public String getTimeZoneID() {
|
||||
TimeZone tz = TimeZone.getDefault();
|
||||
return(tz.getID());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getTimeZoneID() {
|
||||
TimeZone tz = TimeZone.getDefault();
|
||||
return (tz.getID());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,127 +25,127 @@ import android.os.Environment;
|
||||
import android.os.StatFs;
|
||||
|
||||
/**
|
||||
* This class provides file directory utilities.
|
||||
* This class provides file directory utilities.
|
||||
* All file operations are performed on the SD card.
|
||||
*
|
||||
*
|
||||
* It is used by the FileUtils class.
|
||||
*/
|
||||
public class DirectoryManager {
|
||||
|
||||
private static final String LOG_TAG = "DirectoryManager";
|
||||
|
||||
/**
|
||||
* Determine if a file or directory exists.
|
||||
*
|
||||
* @param name The name of the file to check.
|
||||
* @return T=exists, F=not found
|
||||
*/
|
||||
protected static boolean testFileExists(String name) {
|
||||
boolean status;
|
||||
|
||||
// If SD card exists
|
||||
if ((testSaveLocationExists()) && (!name.equals(""))) {
|
||||
File path = Environment.getExternalStorageDirectory();
|
||||
@SuppressWarnings("unused")
|
||||
private static final String LOG_TAG = "DirectoryManager";
|
||||
|
||||
/**
|
||||
* Determine if a file or directory exists.
|
||||
* @param name The name of the file to check.
|
||||
* @return T=exists, F=not found
|
||||
*/
|
||||
protected static boolean testFileExists(String name) {
|
||||
boolean status;
|
||||
|
||||
// If SD card exists
|
||||
if ((testSaveLocationExists()) && (!name.equals(""))) {
|
||||
File path = Environment.getExternalStorageDirectory();
|
||||
File newPath = constructFilePaths(path.toString(), name);
|
||||
status = newPath.exists();
|
||||
}
|
||||
// If no SD card
|
||||
else{
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the free disk space
|
||||
*
|
||||
* @return Size in KB or -1 if not available
|
||||
*/
|
||||
protected static long getFreeDiskSpace(boolean checkInternal) {
|
||||
String status = Environment.getExternalStorageState();
|
||||
long freeSpace = 0;
|
||||
|
||||
// If SD card exists
|
||||
if (status.equals(Environment.MEDIA_MOUNTED)) {
|
||||
freeSpace = freeSpaceCalculation(Environment.getExternalStorageDirectory().getPath());
|
||||
}
|
||||
else if (checkInternal) {
|
||||
freeSpace = freeSpaceCalculation("/");
|
||||
}
|
||||
// If no SD card and we haven't been asked to check the internal directory then return -1
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return freeSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a path return the number of free KB
|
||||
*
|
||||
* @param path to the file system
|
||||
* @return free space in KB
|
||||
*/
|
||||
private static long freeSpaceCalculation(String path) {
|
||||
}
|
||||
// If no SD card
|
||||
else {
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the free disk space
|
||||
*
|
||||
* @return Size in KB or -1 if not available
|
||||
*/
|
||||
protected static long getFreeDiskSpace(boolean checkInternal) {
|
||||
String status = Environment.getExternalStorageState();
|
||||
long freeSpace = 0;
|
||||
|
||||
// If SD card exists
|
||||
if (status.equals(Environment.MEDIA_MOUNTED)) {
|
||||
freeSpace = freeSpaceCalculation(Environment.getExternalStorageDirectory().getPath());
|
||||
}
|
||||
else if (checkInternal) {
|
||||
freeSpace = freeSpaceCalculation("/");
|
||||
}
|
||||
// If no SD card and we haven't been asked to check the internal directory then return -1
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return freeSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a path return the number of free KB
|
||||
*
|
||||
* @param path to the file system
|
||||
* @return free space in KB
|
||||
*/
|
||||
private static long freeSpaceCalculation(String path) {
|
||||
StatFs stat = new StatFs(path);
|
||||
long blockSize = stat.getBlockSize();
|
||||
long availableBlocks = stat.getAvailableBlocks();
|
||||
return availableBlocks*blockSize/1024;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if SD card exists.
|
||||
*
|
||||
* @return T=exists, F=not found
|
||||
*/
|
||||
protected static boolean testSaveLocationExists() {
|
||||
String sDCardStatus = Environment.getExternalStorageState();
|
||||
boolean status;
|
||||
|
||||
// If SD card is mounted
|
||||
if (sDCardStatus.equals(Environment.MEDIA_MOUNTED)) {
|
||||
status = true;
|
||||
}
|
||||
|
||||
// If no SD card
|
||||
else {
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new file object from two file paths.
|
||||
*
|
||||
* @param file1 Base file path
|
||||
* @param file2 Remaining file path
|
||||
* @return File object
|
||||
*/
|
||||
private static File constructFilePaths (String file1, String file2) {
|
||||
File newPath;
|
||||
if (file2.startsWith(file1)) {
|
||||
newPath = new File(file2);
|
||||
}
|
||||
else {
|
||||
newPath = new File(file1+"/"+file2);
|
||||
}
|
||||
return newPath;
|
||||
}
|
||||
|
||||
return availableBlocks * blockSize / 1024;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we can use the SD Card to store the temporary file. If not then use
|
||||
* the internal cache directory.
|
||||
* Determine if SD card exists.
|
||||
*
|
||||
* @return T=exists, F=not found
|
||||
*/
|
||||
protected static boolean testSaveLocationExists() {
|
||||
String sDCardStatus = Environment.getExternalStorageState();
|
||||
boolean status;
|
||||
|
||||
// If SD card is mounted
|
||||
if (sDCardStatus.equals(Environment.MEDIA_MOUNTED)) {
|
||||
status = true;
|
||||
}
|
||||
|
||||
// If no SD card
|
||||
else {
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new file object from two file paths.
|
||||
*
|
||||
* @param file1 Base file path
|
||||
* @param file2 Remaining file path
|
||||
* @return File object
|
||||
*/
|
||||
private static File constructFilePaths (String file1, String file2) {
|
||||
File newPath;
|
||||
if (file2.startsWith(file1)) {
|
||||
newPath = new File(file2);
|
||||
}
|
||||
else {
|
||||
newPath = new File(file1 + "/" + file2);
|
||||
}
|
||||
return newPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we can use the SD Card to store the temporary file. If not then use
|
||||
* the internal cache directory.
|
||||
*
|
||||
* @return the absolute path of where to store the file
|
||||
*/
|
||||
protected static String getTempDirectoryPath(Context ctx) {
|
||||
File cache = null;
|
||||
|
||||
|
||||
// SD Card Mounted
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
cache = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
|
||||
cache = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
|
||||
"/Android/data/" + ctx.getPackageName() + "/cache/");
|
||||
}
|
||||
}
|
||||
// Use internal storage
|
||||
else {
|
||||
cache = ctx.getCacheDir();
|
||||
|
||||
@@ -41,31 +41,31 @@ public class ExifHelper {
|
||||
private String make = null;
|
||||
private String model = null;
|
||||
private String orientation = null;
|
||||
private String whiteBalance = null;
|
||||
|
||||
private String whiteBalance = null;
|
||||
|
||||
private ExifInterface inFile = null;
|
||||
private ExifInterface outFile = null;
|
||||
|
||||
|
||||
/**
|
||||
* The file before it is compressed
|
||||
*
|
||||
* @param filePath
|
||||
*
|
||||
* @param filePath
|
||||
* @throws IOException
|
||||
*/
|
||||
public void createInFile(String filePath) throws IOException {
|
||||
this.inFile = new ExifInterface(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* The file after it has been compressed
|
||||
*
|
||||
*
|
||||
* @param filePath
|
||||
* @throws IOException
|
||||
*/
|
||||
public void createOutFile(String filePath) throws IOException {
|
||||
this.outFile = new ExifInterface(filePath);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads all the EXIF data from the input file.
|
||||
*/
|
||||
@@ -88,12 +88,12 @@ public class ExifHelper {
|
||||
this.make = inFile.getAttribute(ExifInterface.TAG_MAKE);
|
||||
this.model = inFile.getAttribute(ExifInterface.TAG_MODEL);
|
||||
this.orientation = inFile.getAttribute(ExifInterface.TAG_ORIENTATION);
|
||||
this.whiteBalance = inFile.getAttribute(ExifInterface.TAG_WHITE_BALANCE);
|
||||
this.whiteBalance = inFile.getAttribute(ExifInterface.TAG_WHITE_BALANCE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes the previously stored EXIF data to the output file.
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeExifData() throws IOException {
|
||||
@@ -101,7 +101,7 @@ public class ExifHelper {
|
||||
if (this.outFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (this.aperature != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_APERTURE, this.aperature);
|
||||
}
|
||||
@@ -159,7 +159,7 @@ public class ExifHelper {
|
||||
if (this.whiteBalance != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_WHITE_BALANCE, this.whiteBalance);
|
||||
}
|
||||
|
||||
|
||||
this.outFile.saveAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.webkit.CookieManager;
|
||||
|
||||
|
||||
public class FileTransfer extends Plugin {
|
||||
|
||||
private static final String LOG_TAG = "FileTransfer";
|
||||
@@ -76,8 +75,7 @@ public class FileTransfer extends Plugin {
|
||||
try {
|
||||
source = args.getString(0);
|
||||
target = args.getString(1);
|
||||
}
|
||||
catch (JSONException e) {
|
||||
} catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "Missing source or target");
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Missing source or target");
|
||||
}
|
||||
@@ -221,9 +219,11 @@ public class FileTransfer extends Plugin {
|
||||
|
||||
extraParams += LINE_START + BOUNDARY + LINE_END;
|
||||
extraParams += "Content-Disposition: form-data; name=\"" + fileKey + "\";" + " filename=\"";
|
||||
byte[] extraBytes = extraParams.getBytes("UTF-8");
|
||||
|
||||
String midParams = "\"" + LINE_END + "Content-Type: " + mimeType + LINE_END + LINE_END;
|
||||
String tailParams = LINE_END + LINE_START + BOUNDARY + LINE_START + LINE_END;
|
||||
byte[] fileNameBytes = fileName.getBytes("UTF-8");
|
||||
|
||||
// Should set this up as an option
|
||||
if (chunkedMode) {
|
||||
@@ -231,7 +231,7 @@ public class FileTransfer extends Plugin {
|
||||
}
|
||||
else
|
||||
{
|
||||
int stringLength = extraParams.length() + midParams.length() + tailParams.length() + fileName.getBytes("UTF-8").length;
|
||||
int stringLength = extraBytes.length + midParams.length() + tailParams.length() + fileNameBytes.length;
|
||||
Log.d(LOG_TAG, "String Length: " + stringLength);
|
||||
int fixedLength = (int) fileInputStream.getChannel().size() + stringLength;
|
||||
Log.d(LOG_TAG, "Content Length: " + fixedLength);
|
||||
@@ -240,9 +240,9 @@ public class FileTransfer extends Plugin {
|
||||
|
||||
|
||||
dos = new DataOutputStream( conn.getOutputStream() );
|
||||
dos.writeBytes(extraParams);
|
||||
//We don't want to chagne encoding, we just want this to write for all Unicode.
|
||||
dos.write(fileName.getBytes("UTF-8"));
|
||||
//We don't want to change encoding, we just want this to write for all Unicode.
|
||||
dos.write(extraBytes);
|
||||
dos.write(fileNameBytes);
|
||||
dos.writeBytes(midParams);
|
||||
|
||||
// create a buffer of maximum size
|
||||
@@ -353,11 +353,11 @@ public class FileTransfer extends Plugin {
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] chain,
|
||||
String authType) throws CertificateException {
|
||||
String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] chain,
|
||||
String authType) throws CertificateException {
|
||||
String authType) throws CertificateException {
|
||||
}
|
||||
} };
|
||||
|
||||
@@ -419,7 +419,7 @@ public class FileTransfer extends Plugin {
|
||||
*/
|
||||
private String getArgument(JSONArray args, int position, String defaultString) {
|
||||
String arg = defaultString;
|
||||
if(args.length() >= position) {
|
||||
if (args.length() >= position) {
|
||||
arg = args.optString(position);
|
||||
if (arg == null || "null".equals(arg)) {
|
||||
arg = defaultString;
|
||||
@@ -428,7 +428,6 @@ public class FileTransfer extends Plugin {
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Downloads a file form a given URL and saves it to the specified directory.
|
||||
*
|
||||
@@ -447,37 +446,41 @@ public class FileTransfer extends Plugin {
|
||||
file.getParentFile().mkdirs();
|
||||
|
||||
// connect to server
|
||||
if(this.ctx.isUrlWhiteListed(source))
|
||||
if (webView.isUrlWhiteListed(source))
|
||||
{
|
||||
URL url = new URL(source);
|
||||
connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
|
||||
|
||||
//Add cookie support
|
||||
String cookie = CookieManager.getInstance().getCookie(source);
|
||||
if(cookie != null)
|
||||
{
|
||||
connection.setRequestProperty("cookie", cookie);
|
||||
}
|
||||
|
||||
|
||||
connection.connect();
|
||||
|
||||
Log.d(LOG_TAG, "Download file: " + url);
|
||||
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead = 0;
|
||||
connection.connect();
|
||||
|
||||
FileOutputStream outputStream = new FileOutputStream(file);
|
||||
Log.d(LOG_TAG, "Download file:" + url);
|
||||
|
||||
// write bytes to file
|
||||
while ( (bytesRead = inputStream.read(buffer)) > 0 ) {
|
||||
outputStream.write(buffer,0, bytesRead);
|
||||
}
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead = 0;
|
||||
|
||||
outputStream.close();
|
||||
FileOutputStream outputStream = new FileOutputStream(file);
|
||||
|
||||
Log.d(LOG_TAG, "Saved file: " + target);
|
||||
// write bytes to file
|
||||
while ((bytesRead = inputStream.read(buffer)) > 0) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
outputStream.close();
|
||||
|
||||
Log.d(LOG_TAG, "Saved file: " + target);
|
||||
|
||||
// create FileEntry object
|
||||
FileUtils fileUtil = new FileUtils();
|
||||
@@ -521,7 +524,7 @@ public class FileTransfer extends Plugin {
|
||||
private InputStream getPathFromUri(String path) throws FileNotFoundException {
|
||||
if (path.startsWith("content:")) {
|
||||
Uri uri = Uri.parse(path);
|
||||
return ctx.getContentResolver().openInputStream(uri);
|
||||
return cordova.getActivity().getContentResolver().openInputStream(uri);
|
||||
}
|
||||
else if (path.startsWith("file://")) {
|
||||
int question = path.indexOf("?");
|
||||
@@ -538,7 +541,7 @@ public class FileTransfer extends Plugin {
|
||||
|
||||
/**
|
||||
* Get a File object from the passed in path
|
||||
*
|
||||
*
|
||||
* @param path file path
|
||||
* @return file object
|
||||
*/
|
||||
|
||||
@@ -25,39 +25,39 @@ import org.json.JSONObject;
|
||||
* Encapsulates the result and/or status of uploading a file to a remote server.
|
||||
*/
|
||||
public class FileUploadResult {
|
||||
|
||||
|
||||
private long bytesSent = 0; // bytes sent
|
||||
private int responseCode = -1; // HTTP response code
|
||||
private String response = null; // HTTP response
|
||||
|
||||
|
||||
public long getBytesSent() {
|
||||
return bytesSent;
|
||||
}
|
||||
|
||||
|
||||
public void setBytesSent(long bytes) {
|
||||
this.bytesSent = bytes;
|
||||
}
|
||||
|
||||
|
||||
public int getResponseCode() {
|
||||
return responseCode;
|
||||
}
|
||||
|
||||
|
||||
public void setResponseCode(int responseCode) {
|
||||
this.responseCode = responseCode;
|
||||
}
|
||||
|
||||
|
||||
public String getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
public void setResponse(String response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public JSONObject toJSONObject() throws JSONException {
|
||||
return new JSONObject(
|
||||
"{bytesSent:" + bytesSent +
|
||||
",responseCode:" + responseCode +
|
||||
"{bytesSent:" + bytesSent +
|
||||
",responseCode:" + responseCode +
|
||||
",response:" + JSONObject.quote(response) + "}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,19 +37,21 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
//import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
//import android.app.Activity;
|
||||
|
||||
/**
|
||||
* This class provides SD card file and directory services to JavaScript.
|
||||
* Only files on the SD card can be accessed.
|
||||
*/
|
||||
public class FileUtils extends Plugin {
|
||||
@SuppressWarnings("unused")
|
||||
private static final String LOG_TAG = "FileUtils";
|
||||
private static final String _DATA = "_data"; // The column name where the file path is stored
|
||||
|
||||
@@ -130,7 +132,7 @@ public class FileUtils extends Plugin {
|
||||
else if (action.equals("requestFileSystem")) {
|
||||
long size = args.optLong(1);
|
||||
if (size != 0) {
|
||||
if (size > (DirectoryManager.getFreeDiskSpace(true)*1024)) {
|
||||
if (size > (DirectoryManager.getFreeDiskSpace(true) * 1024)) {
|
||||
return new PluginResult(PluginResult.Status.ERROR, FileUtils.QUOTA_EXCEEDED_ERR);
|
||||
}
|
||||
}
|
||||
@@ -221,9 +223,9 @@ public class FileUtils extends Plugin {
|
||||
*/
|
||||
private void notifyDelete(String filePath) {
|
||||
String newFilePath = stripFileProtocol(filePath);
|
||||
int result = this.ctx.getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
MediaStore.Images.Media.DATA + " = ?",
|
||||
new String[] {newFilePath});
|
||||
int result = this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
MediaStore.Images.Media.DATA + " = ?",
|
||||
new String[] { newFilePath });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,6 +238,7 @@ public class FileUtils extends Plugin {
|
||||
* @throws IOException if the user can't read the file
|
||||
* @throws JSONException
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private JSONObject resolveLocalFileSystemURI(String url) throws IOException, JSONException {
|
||||
String decoded = URLDecoder.decode(url, "UTF-8");
|
||||
|
||||
@@ -243,7 +246,7 @@ public class FileUtils extends Plugin {
|
||||
|
||||
// Handle the special case where you get an Android content:// uri.
|
||||
if (decoded.startsWith("content:")) {
|
||||
Cursor cursor = this.ctx.managedQuery(Uri.parse(decoded), new String[] { MediaStore.Images.Media.DATA }, null, null, null);
|
||||
Cursor cursor = this.cordova.getActivity().managedQuery(Uri.parse(decoded), new String[] { MediaStore.Images.Media.DATA }, null, null, null);
|
||||
// Note: MediaStore.Images/Audio/Video.Media.DATA is always "_data"
|
||||
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
|
||||
cursor.moveToFirst();
|
||||
@@ -294,7 +297,7 @@ public class FileUtils extends Plugin {
|
||||
|
||||
if (fp.isDirectory()) {
|
||||
File[] files = fp.listFiles();
|
||||
for (int i=0; i<files.length; i++) {
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
entries.put(getEntry(files[i]));
|
||||
}
|
||||
}
|
||||
@@ -320,7 +323,6 @@ public class FileUtils extends Plugin {
|
||||
fileName = stripFileProtocol(fileName);
|
||||
newParent = stripFileProtocol(newParent);
|
||||
|
||||
|
||||
// Check for invalid file name
|
||||
if (newName != null && newName.contains(":")) {
|
||||
throw new EncodingException("Bad file name");
|
||||
@@ -377,7 +379,7 @@ public class FileUtils extends Plugin {
|
||||
File destFile = null;
|
||||
|
||||
// I know this looks weird but it is to work around a JSON bug.
|
||||
if ("null".equals(newName) || "".equals(newName) ) {
|
||||
if ("null".equals(newName) || "".equals(newName)) {
|
||||
newName = null;
|
||||
}
|
||||
|
||||
@@ -399,7 +401,7 @@ public class FileUtils extends Plugin {
|
||||
* @throws InvalidModificationException
|
||||
* @throws JSONException
|
||||
*/
|
||||
private JSONObject copyFile(File srcFile, File destFile) throws IOException, InvalidModificationException, JSONException {
|
||||
private JSONObject copyFile(File srcFile, File destFile) throws IOException, InvalidModificationException, JSONException {
|
||||
// Renaming a file to an existing directory should fail
|
||||
if (destFile.exists() && destFile.isDirectory()) {
|
||||
throw new InvalidModificationException("Can't rename a file to a directory");
|
||||
@@ -477,7 +479,7 @@ public class FileUtils extends Plugin {
|
||||
// This weird test is to determine if we are copying or moving a directory into itself.
|
||||
// Copy /sdcard/myDir to /sdcard/myDir-backup is okay but
|
||||
// Copy /sdcard/myDir to /sdcard/myDir/backup should thow an INVALID_MODIFICATION_ERR
|
||||
if (dest.startsWith(src) && dest.indexOf(File.separator, src.length()-1) != -1) {
|
||||
if (dest.startsWith(src) && dest.indexOf(File.separator, src.length() - 1) != -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -726,9 +728,9 @@ public class FileUtils extends Plugin {
|
||||
private boolean atRootDirectory(String filePath) {
|
||||
filePath = stripFileProtocol(filePath);
|
||||
|
||||
if (filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + ctx.getPackageName() + "/cache") ||
|
||||
filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath()) ||
|
||||
filePath.equals("/data/data/" + ctx.getPackageName())) {
|
||||
if (filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + cordova.getActivity().getPackageName() + "/cache") ||
|
||||
filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath()) ||
|
||||
filePath.equals("/data/data/" + cordova.getActivity().getPackageName())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -736,7 +738,7 @@ public class FileUtils extends Plugin {
|
||||
|
||||
/**
|
||||
* This method removes the "file://" from the passed in filePath
|
||||
*
|
||||
*
|
||||
* @param filePath to be checked.
|
||||
* @return
|
||||
*/
|
||||
@@ -746,10 +748,10 @@ public class FileUtils extends Plugin {
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a File object from the passed in path
|
||||
*
|
||||
*
|
||||
* @param filePath
|
||||
* @return
|
||||
*/
|
||||
@@ -792,7 +794,7 @@ public class FileUtils extends Plugin {
|
||||
throw new FileNotFoundException("File: " + filePath + " does not exist.");
|
||||
}
|
||||
|
||||
JSONObject metadata = new JSONObject();
|
||||
JSONObject metadata = new JSONObject();
|
||||
metadata.put("size", file.length());
|
||||
metadata.put("type", getMimeType(filePath));
|
||||
metadata.put("name", file.getName());
|
||||
@@ -817,16 +819,16 @@ public class FileUtils extends Plugin {
|
||||
fs.put("name", "temporary");
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
fp = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
|
||||
"/Android/data/" + ctx.getPackageName() + "/cache/");
|
||||
"/Android/data/" + cordova.getActivity().getPackageName() + "/cache/");
|
||||
// Create the cache dir if it doesn't exist.
|
||||
fp.mkdirs();
|
||||
fs.put("root", getEntry(Environment.getExternalStorageDirectory().getAbsolutePath() +
|
||||
"/Android/data/" + ctx.getPackageName() + "/cache/"));
|
||||
"/Android/data/" + cordova.getActivity().getPackageName() + "/cache/"));
|
||||
} else {
|
||||
fp = new File("/data/data/" + ctx.getPackageName() + "/cache/");
|
||||
fp = new File("/data/data/" + cordova.getActivity().getPackageName() + "/cache/");
|
||||
// Create the cache dir if it doesn't exist.
|
||||
fp.mkdirs();
|
||||
fs.put("root", getEntry("/data/data/" + ctx.getPackageName() + "/cache/"));
|
||||
fs.put("root", getEntry("/data/data/" + cordova.getActivity().getPackageName() + "/cache/"));
|
||||
}
|
||||
}
|
||||
else if (type == PERSISTENT) {
|
||||
@@ -834,13 +836,13 @@ public class FileUtils extends Plugin {
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
fs.put("root", getEntry(Environment.getExternalStorageDirectory()));
|
||||
} else {
|
||||
fs.put("root", getEntry("/data/data/" + ctx.getPackageName()));
|
||||
fs.put("root", getEntry("/data/data/" + cordova.getActivity().getPackageName()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IOException("No filesystem of type requested");
|
||||
}
|
||||
|
||||
|
||||
return fs;
|
||||
}
|
||||
|
||||
@@ -941,7 +943,7 @@ public class FileUtils extends Plugin {
|
||||
String contentType = null;
|
||||
if (filename.startsWith("content:")) {
|
||||
Uri fileUri = Uri.parse(filename);
|
||||
contentType = this.ctx.getContentResolver().getType(fileUri);
|
||||
contentType = this.cordova.getActivity().getContentResolver().getType(fileUri);
|
||||
}
|
||||
else {
|
||||
contentType = getMimeType(filename);
|
||||
@@ -960,7 +962,7 @@ public class FileUtils extends Plugin {
|
||||
*/
|
||||
public static String getMimeType(String filename) {
|
||||
MimeTypeMap map = MimeTypeMap.getSingleton();
|
||||
return map.getMimeTypeFromExtension(map.getFileExtensionFromUrl(filename));
|
||||
return map.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(filename));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -974,14 +976,14 @@ public class FileUtils extends Plugin {
|
||||
/**/
|
||||
public long write(String filename, String data, int offset) throws FileNotFoundException, IOException {
|
||||
filename = stripFileProtocol(filename);
|
||||
|
||||
|
||||
boolean append = false;
|
||||
if (offset > 0) {
|
||||
this.truncateFile(filename, offset);
|
||||
append = true;
|
||||
}
|
||||
|
||||
byte [] rawData = data.getBytes();
|
||||
byte[] rawData = data.getBytes();
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(rawData);
|
||||
FileOutputStream out = new FileOutputStream(filename, append);
|
||||
byte buff[] = new byte[rawData.length];
|
||||
@@ -1006,9 +1008,9 @@ public class FileUtils extends Plugin {
|
||||
RandomAccessFile raf = new RandomAccessFile(filename, "rw");
|
||||
|
||||
if (raf.length() >= size) {
|
||||
FileChannel channel = raf.getChannel();
|
||||
channel.truncate(size);
|
||||
return size;
|
||||
FileChannel channel = raf.getChannel();
|
||||
channel.truncate(size);
|
||||
return size;
|
||||
}
|
||||
|
||||
return raf.length();
|
||||
@@ -1024,7 +1026,7 @@ public class FileUtils extends Plugin {
|
||||
private InputStream getPathFromUri(String path) throws FileNotFoundException {
|
||||
if (path.startsWith("content")) {
|
||||
Uri uri = Uri.parse(path);
|
||||
return ctx.getContentResolver().openInputStream(uri);
|
||||
return cordova.getActivity().getContentResolver().openInputStream(uri);
|
||||
}
|
||||
else {
|
||||
path = stripFileProtocol(path);
|
||||
@@ -1036,12 +1038,13 @@ public class FileUtils extends Plugin {
|
||||
* Queries the media store to find out what the file path is for the Uri we supply
|
||||
*
|
||||
* @param contentUri the Uri of the audio/image/video
|
||||
* @param ctx the current applicaiton context
|
||||
* @param cordova) the current applicaiton context
|
||||
* @return the full path to the file
|
||||
*/
|
||||
protected static String getRealPathFromURI(Uri contentUri, CordovaInterface ctx) {
|
||||
@SuppressWarnings("deprecation")
|
||||
protected static String getRealPathFromURI(Uri contentUri, CordovaInterface cordova) {
|
||||
String[] proj = { _DATA };
|
||||
Cursor cursor = ctx.managedQuery(contentUri, proj, null, null, null);
|
||||
Cursor cursor = cordova.getActivity().managedQuery(contentUri, proj, null, null, null);
|
||||
int column_index = cursor.getColumnIndexOrThrow(_DATA);
|
||||
cursor.moveToFirst();
|
||||
return cursor.getString(column_index);
|
||||
|
||||
@@ -26,25 +26,25 @@ import android.location.LocationManager;
|
||||
*
|
||||
*/
|
||||
public class GPSListener extends CordovaLocationListener {
|
||||
public GPSListener(LocationManager locationManager, GeoBroker m) {
|
||||
super(locationManager, m, "[Cordova GPSListener]");
|
||||
}
|
||||
public GPSListener(LocationManager locationManager, GeoBroker m) {
|
||||
super(locationManager, m, "[Cordova GPSListener]");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start requesting location updates.
|
||||
*
|
||||
* @param interval
|
||||
*/
|
||||
@Override
|
||||
protected void start() {
|
||||
if (!this.running) {
|
||||
if (this.locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
|
||||
this.running = true;
|
||||
this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, this);
|
||||
} else {
|
||||
this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "GPS provider is not available.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start requesting location updates.
|
||||
*
|
||||
* @param interval
|
||||
*/
|
||||
@Override
|
||||
protected void start() {
|
||||
if (!this.running) {
|
||||
if (this.locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
|
||||
this.running = true;
|
||||
this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, this);
|
||||
} else {
|
||||
this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "GPS provider is not available.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import android.location.LocationManager;
|
||||
|
||||
/*
|
||||
* This class is the interface to the Geolocation. It's bound to the geo object.
|
||||
*
|
||||
*
|
||||
* This class only starts and stops various GeoListeners, which consist of a GPS and a Network Listener
|
||||
*/
|
||||
|
||||
@@ -38,7 +38,7 @@ public class GeoBroker extends Plugin {
|
||||
private GPSListener gpsListener;
|
||||
private NetworkListener networkListener;
|
||||
private LocationManager locationManager;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -47,74 +47,74 @@ public class GeoBroker extends Plugin {
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
if (this.locationManager == null) {
|
||||
this.locationManager = (LocationManager) this.ctx.getSystemService(Context.LOCATION_SERVICE);
|
||||
this.networkListener = new NetworkListener(this.locationManager, this);
|
||||
this.gpsListener = new GPSListener(this.locationManager, this);
|
||||
}
|
||||
if (this.locationManager == null) {
|
||||
this.locationManager = (LocationManager) this.cordova.getActivity().getSystemService(Context.LOCATION_SERVICE);
|
||||
this.networkListener = new NetworkListener(this.locationManager, this);
|
||||
this.gpsListener = new GPSListener(this.locationManager, this);
|
||||
}
|
||||
PluginResult.Status status = PluginResult.Status.NO_RESULT;
|
||||
String message = "";
|
||||
PluginResult result = new PluginResult(status, message);
|
||||
result.setKeepCallback(true);
|
||||
|
||||
|
||||
try {
|
||||
if (action.equals("getLocation")) {
|
||||
boolean enableHighAccuracy = args.getBoolean(0);
|
||||
int maximumAge = args.getInt(1);
|
||||
Location last = this.locationManager.getLastKnownLocation((enableHighAccuracy ? LocationManager.GPS_PROVIDER : LocationManager.NETWORK_PROVIDER));
|
||||
// Check if we can use lastKnownLocation to get a quick reading and use less battery
|
||||
if ((System.currentTimeMillis() - last.getTime()) <= maximumAge) {
|
||||
result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(last));
|
||||
} else {
|
||||
this.getCurrentLocation(callbackId, enableHighAccuracy);
|
||||
}
|
||||
boolean enableHighAccuracy = args.getBoolean(0);
|
||||
int maximumAge = args.getInt(1);
|
||||
Location last = this.locationManager.getLastKnownLocation((enableHighAccuracy ? LocationManager.GPS_PROVIDER : LocationManager.NETWORK_PROVIDER));
|
||||
// Check if we can use lastKnownLocation to get a quick reading and use less battery
|
||||
if ((System.currentTimeMillis() - last.getTime()) <= maximumAge) {
|
||||
result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(last));
|
||||
} else {
|
||||
this.getCurrentLocation(callbackId, enableHighAccuracy);
|
||||
}
|
||||
}
|
||||
else if (action.equals("addWatch")) {
|
||||
String id = args.getString(0);
|
||||
boolean enableHighAccuracy = args.getBoolean(1);
|
||||
this.addWatch(id, callbackId, enableHighAccuracy);
|
||||
String id = args.getString(0);
|
||||
boolean enableHighAccuracy = args.getBoolean(1);
|
||||
this.addWatch(id, callbackId, enableHighAccuracy);
|
||||
}
|
||||
else if (action.equals("clearWatch")) {
|
||||
String id = args.getString(0);
|
||||
this.clearWatch(id);
|
||||
String id = args.getString(0);
|
||||
this.clearWatch(id);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
|
||||
result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void clearWatch(String id) {
|
||||
this.gpsListener.clearWatch(id);
|
||||
this.networkListener.clearWatch(id);
|
||||
}
|
||||
|
||||
private void getCurrentLocation(String callbackId, boolean enableHighAccuracy) {
|
||||
if (enableHighAccuracy) {
|
||||
this.gpsListener.addCallback(callbackId);
|
||||
} else {
|
||||
this.networkListener.addCallback(callbackId);
|
||||
}
|
||||
}
|
||||
|
||||
private void addWatch(String timerId, String callbackId, boolean enableHighAccuracy) {
|
||||
if (enableHighAccuracy) {
|
||||
this.gpsListener.addWatch(timerId, callbackId);
|
||||
} else {
|
||||
this.networkListener.addWatch(timerId, callbackId);
|
||||
}
|
||||
this.gpsListener.clearWatch(id);
|
||||
this.networkListener.clearWatch(id);
|
||||
}
|
||||
|
||||
/**
|
||||
private void getCurrentLocation(String callbackId, boolean enableHighAccuracy) {
|
||||
if (enableHighAccuracy) {
|
||||
this.gpsListener.addCallback(callbackId);
|
||||
} else {
|
||||
this.networkListener.addCallback(callbackId);
|
||||
}
|
||||
}
|
||||
|
||||
private void addWatch(String timerId, String callbackId, boolean enableHighAccuracy) {
|
||||
if (enableHighAccuracy) {
|
||||
this.gpsListener.addWatch(timerId, callbackId);
|
||||
} else {
|
||||
this.networkListener.addWatch(timerId, callbackId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
@@ -122,65 +122,66 @@ public class GeoBroker extends Plugin {
|
||||
// Starting listeners is easier to run on main thread, so don't run async.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when the activity is to be shut down.
|
||||
* Stop listener.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
this.networkListener.destroy();
|
||||
this.gpsListener.destroy();
|
||||
this.networkListener.destroy();
|
||||
this.gpsListener.destroy();
|
||||
this.networkListener = null;
|
||||
this.gpsListener = null;
|
||||
}
|
||||
|
||||
public JSONObject returnLocationJSON(Location loc) {
|
||||
JSONObject o = new JSONObject();
|
||||
|
||||
try {
|
||||
o.put("latitude", loc.getLatitude());
|
||||
o.put("longitude", loc.getLongitude());
|
||||
o.put("altitude", (loc.hasAltitude() ? loc.getAltitude() : null));
|
||||
o.put("accuracy", loc.getAccuracy());
|
||||
o.put("heading", (loc.hasBearing() ? (loc.hasSpeed() ? loc.getBearing() : null) : null));
|
||||
o.put("speed", loc.getSpeed());
|
||||
o.put("timestamp", loc.getTime());
|
||||
} catch (JSONException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
return o;
|
||||
}
|
||||
public void win(Location loc, String callbackId) {
|
||||
PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc));
|
||||
this.success(result, callbackId);
|
||||
}
|
||||
/**
|
||||
* Location failed. Send error back to JavaScript.
|
||||
*
|
||||
* @param code The error code
|
||||
* @param msg The error message
|
||||
* @throws JSONException
|
||||
*/
|
||||
public void fail(int code, String msg, String callbackId) {
|
||||
JSONObject obj = new JSONObject();
|
||||
String backup = null;
|
||||
try {
|
||||
obj.put("code", code);
|
||||
obj.put("message", msg);
|
||||
} catch (JSONException e) {
|
||||
obj = null;
|
||||
backup = "{'code':" + code + ",'message':'" + msg.replaceAll("'", "\'") + "'}";
|
||||
}
|
||||
PluginResult result;
|
||||
if (obj != null) {
|
||||
result = new PluginResult(PluginResult.Status.ERROR, obj);
|
||||
} else {
|
||||
result = new PluginResult(PluginResult.Status.ERROR, backup);
|
||||
}
|
||||
|
||||
this.error(result, callbackId);
|
||||
}
|
||||
JSONObject o = new JSONObject();
|
||||
|
||||
try {
|
||||
o.put("latitude", loc.getLatitude());
|
||||
o.put("longitude", loc.getLongitude());
|
||||
o.put("altitude", (loc.hasAltitude() ? loc.getAltitude() : null));
|
||||
o.put("accuracy", loc.getAccuracy());
|
||||
o.put("heading", (loc.hasBearing() ? (loc.hasSpeed() ? loc.getBearing() : null) : null));
|
||||
o.put("speed", loc.getSpeed());
|
||||
o.put("timestamp", loc.getTime());
|
||||
} catch (JSONException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
public void win(Location loc, String callbackId) {
|
||||
PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc));
|
||||
this.success(result, callbackId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Location failed. Send error back to JavaScript.
|
||||
*
|
||||
* @param code The error code
|
||||
* @param msg The error message
|
||||
* @throws JSONException
|
||||
*/
|
||||
public void fail(int code, String msg, String callbackId) {
|
||||
JSONObject obj = new JSONObject();
|
||||
String backup = null;
|
||||
try {
|
||||
obj.put("code", code);
|
||||
obj.put("message", msg);
|
||||
} catch (JSONException e) {
|
||||
obj = null;
|
||||
backup = "{'code':" + code + ",'message':'" + msg.replaceAll("'", "\'") + "'}";
|
||||
}
|
||||
PluginResult result;
|
||||
if (obj != null) {
|
||||
result = new PluginResult(PluginResult.Status.ERROR, obj);
|
||||
} else {
|
||||
result = new PluginResult(PluginResult.Status.ERROR, backup);
|
||||
}
|
||||
|
||||
this.error(result, callbackId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,52 +29,58 @@ import org.apache.http.impl.client.DefaultHttpClient;
|
||||
|
||||
public class HttpHandler {
|
||||
|
||||
protected Boolean get(String url, String file)
|
||||
{
|
||||
HttpEntity entity = getHttpEntity(url);
|
||||
try {
|
||||
writeToDisk(entity, file);
|
||||
} catch (Exception e) { e.printStackTrace(); return false; }
|
||||
try {
|
||||
entity.consumeContent();
|
||||
} catch (Exception e) { e.printStackTrace(); return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
private HttpEntity getHttpEntity(String url)
|
||||
/**
|
||||
* get the http entity at a given url
|
||||
*/
|
||||
{
|
||||
HttpEntity entity=null;
|
||||
try {
|
||||
DefaultHttpClient httpclient = new DefaultHttpClient();
|
||||
HttpGet httpget = new HttpGet(url);
|
||||
HttpResponse response = httpclient.execute(httpget);
|
||||
entity = response.getEntity();
|
||||
} catch (Exception e) { e.printStackTrace(); return null; }
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void writeToDisk(HttpEntity entity, String file) throws IllegalStateException, IOException
|
||||
/**
|
||||
* writes a HTTP entity to the specified filename and location on disk
|
||||
*/
|
||||
{
|
||||
int i=0;
|
||||
String FilePath="/sdcard/" + file;
|
||||
InputStream in = entity.getContent();
|
||||
byte buff[] = new byte[1024];
|
||||
FileOutputStream out=
|
||||
new FileOutputStream(FilePath);
|
||||
do {
|
||||
int numread = in.read(buff);
|
||||
if (numread <= 0)
|
||||
break;
|
||||
out.write(buff, 0, numread);
|
||||
i++;
|
||||
} while (true);
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
protected Boolean get(String url, String file)
|
||||
{
|
||||
HttpEntity entity = getHttpEntity(url);
|
||||
try {
|
||||
writeToDisk(entity, file);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
entity.consumeContent();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private HttpEntity getHttpEntity(String url)
|
||||
/**
|
||||
* get the http entity at a given url
|
||||
*/
|
||||
{
|
||||
HttpEntity entity = null;
|
||||
try {
|
||||
DefaultHttpClient httpclient = new DefaultHttpClient();
|
||||
HttpGet httpget = new HttpGet(url);
|
||||
HttpResponse response = httpclient.execute(httpget);
|
||||
entity = response.getEntity();
|
||||
} catch (Exception e) { e.printStackTrace(); return null; }
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void writeToDisk(HttpEntity entity, String file) throws IllegalStateException, IOException
|
||||
/**
|
||||
* writes a HTTP entity to the specified filename and location on disk
|
||||
*/
|
||||
{
|
||||
//int i = 0;
|
||||
String FilePath = "/sdcard/" + file;
|
||||
InputStream in = entity.getContent();
|
||||
byte buff[] = new byte[1024];
|
||||
FileOutputStream out =
|
||||
new FileOutputStream(FilePath);
|
||||
do {
|
||||
int numread = in.read(buff);
|
||||
if (numread <= 0)
|
||||
break;
|
||||
out.write(buff, 0, numread);
|
||||
//i++;
|
||||
} while (true);
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
under the License.
|
||||
*/
|
||||
package org.apache.cordova;
|
||||
|
||||
import org.apache.cordova.api.LOG;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View.MeasureSpec;
|
||||
//import android.view.View.MeasureSpec;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
/**
|
||||
@@ -29,15 +30,15 @@ import android.widget.LinearLayout;
|
||||
public class LinearLayoutSoftKeyboardDetect extends LinearLayout {
|
||||
|
||||
private static final String TAG = "SoftKeyboardDetect";
|
||||
|
||||
|
||||
private int oldHeight = 0; // Need to save the old height as not to send redundant events
|
||||
private int oldWidth = 0; // Need to save old width for orientation change
|
||||
private int oldWidth = 0; // Need to save old width for orientation change
|
||||
private int screenWidth = 0;
|
||||
private int screenHeight = 0;
|
||||
private DroidGap app = null;
|
||||
|
||||
|
||||
public LinearLayoutSoftKeyboardDetect(Context context, int width, int height) {
|
||||
super(context);
|
||||
super(context);
|
||||
screenWidth = width;
|
||||
screenHeight = height;
|
||||
app = (DroidGap) context;
|
||||
@@ -45,18 +46,18 @@ public class LinearLayoutSoftKeyboardDetect extends LinearLayout {
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Start listening to new measurement events. Fire events when the height
|
||||
* gets smaller fire a show keyboard event and when height gets bigger fire
|
||||
* Start listening to new measurement events. Fire events when the height
|
||||
* gets smaller fire a show keyboard event and when height gets bigger fire
|
||||
* a hide keyboard event.
|
||||
*
|
||||
*
|
||||
* Note: We are using app.postMessage so that this is more compatible with the API
|
||||
*
|
||||
*
|
||||
* @param widthMeasureSpec
|
||||
* @param heightMeasureSpec
|
||||
*/
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
LOG.v(TAG, "We are in our onMeasure method");
|
||||
|
||||
// Get the current height of the visible part of the screen.
|
||||
@@ -66,7 +67,7 @@ public class LinearLayoutSoftKeyboardDetect extends LinearLayout {
|
||||
height = MeasureSpec.getSize(heightMeasureSpec);
|
||||
width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
LOG.v(TAG, "Old Height = %d", oldHeight);
|
||||
LOG.v(TAG, "Height = %d", height);
|
||||
LOG.v(TAG, "Height = %d", height);
|
||||
LOG.v(TAG, "Old Width = %d", oldWidth);
|
||||
LOG.v(TAG, "Width = %d", width);
|
||||
|
||||
@@ -76,24 +77,24 @@ public class LinearLayoutSoftKeyboardDetect extends LinearLayout {
|
||||
LOG.d(TAG, "Ignore this event");
|
||||
}
|
||||
// Account for orientation change and ignore this event/Fire orientation change
|
||||
else if(screenHeight == width)
|
||||
else if (screenHeight == width)
|
||||
{
|
||||
int tmp_var = screenHeight;
|
||||
screenHeight = screenWidth;
|
||||
screenWidth = tmp_var;
|
||||
LOG.v(TAG, "Orientation Change");
|
||||
}
|
||||
// If the height as gotten bigger then we will assume the soft keyboard has
|
||||
// If the height as gotten bigger then we will assume the soft keyboard has
|
||||
// gone away.
|
||||
else if (height > oldHeight) {
|
||||
if(app != null)
|
||||
app.sendJavascript("cordova.fireDocumentEvent('hidekeyboard');");
|
||||
}
|
||||
if (app != null)
|
||||
app.appView.sendJavascript("cordova.fireDocumentEvent('hidekeyboard');");
|
||||
}
|
||||
// If the height as gotten smaller then we will assume the soft keyboard has
|
||||
// been displayed.
|
||||
else if (height < oldHeight) {
|
||||
if(app != null)
|
||||
app.sendJavascript("cordova.fireDocumentEvent('showkeyboard');");
|
||||
if (app != null)
|
||||
app.appView.sendJavascript("cordova.fireDocumentEvent('showkeyboard');");
|
||||
}
|
||||
|
||||
// Update the old height for the next event
|
||||
|
||||
@@ -26,7 +26,7 @@ import android.location.LocationManager;
|
||||
*
|
||||
*/
|
||||
public class NetworkListener extends CordovaLocationListener {
|
||||
public NetworkListener(LocationManager locationManager, GeoBroker m) {
|
||||
super(locationManager, m, "[Cordova NetworkListener]");
|
||||
}
|
||||
public NetworkListener(LocationManager locationManager, GeoBroker m) {
|
||||
super(locationManager, m, "[Cordova NetworkListener]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.apache.cordova.api.Plugin;
|
||||
import org.apache.cordova.api.PluginResult;
|
||||
import org.json.JSONArray;
|
||||
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -33,7 +32,7 @@ import android.net.NetworkInfo;
|
||||
import android.util.Log;
|
||||
|
||||
public class NetworkManager extends Plugin {
|
||||
|
||||
|
||||
public static int NOT_REACHABLE = 0;
|
||||
public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
|
||||
public static int REACHABLE_VIA_WIFI_NETWORK = 2;
|
||||
@@ -66,50 +65,51 @@ public class NetworkManager extends Plugin {
|
||||
public static final String TYPE_3G = "3g";
|
||||
public static final String TYPE_4G = "4g";
|
||||
public static final String TYPE_NONE = "none";
|
||||
|
||||
|
||||
private static final String LOG_TAG = "NetworkManager";
|
||||
|
||||
private String connectionCallbackId;
|
||||
|
||||
ConnectivityManager sockMan;
|
||||
BroadcastReceiver receiver;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public NetworkManager() {
|
||||
public NetworkManager() {
|
||||
this.receiver = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*
|
||||
* @param cordova The context of the main Activity.
|
||||
*/
|
||||
public void setContext(CordovaInterface ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sockMan = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
public void setContext(CordovaInterface cordova) {
|
||||
super.setContext(cordova);
|
||||
this.sockMan = (ConnectivityManager) cordova.getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
this.connectionCallbackId = null;
|
||||
|
||||
|
||||
// We need to listen to connectivity events to update navigator.connection
|
||||
IntentFilter intentFilter = new IntentFilter() ;
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
if (this.receiver == null) {
|
||||
this.receiver = new BroadcastReceiver() {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
updateConnectionInfo((NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO));
|
||||
updateConnectionInfo((NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO));
|
||||
}
|
||||
};
|
||||
ctx.registerReceiver(this.receiver, intentFilter);
|
||||
cordova.getActivity().registerReceiver(this.receiver, intentFilter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
@@ -118,7 +118,7 @@ public class NetworkManager extends Plugin {
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.INVALID_ACTION;
|
||||
String result = "Unsupported Operation: " + action;
|
||||
|
||||
|
||||
if (action.equals("getConnectionInfo")) {
|
||||
this.connectionCallbackId = callbackId;
|
||||
NetworkInfo info = sockMan.getActiveNetworkInfo();
|
||||
@@ -126,27 +126,27 @@ public class NetworkManager extends Plugin {
|
||||
pluginResult.setKeepCallback(true);
|
||||
return pluginResult;
|
||||
}
|
||||
|
||||
|
||||
return new PluginResult(status, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop network receiver.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
if (this.receiver != null) {
|
||||
try {
|
||||
this.ctx.unregisterReceiver(this.receiver);
|
||||
this.cordova.getActivity().unregisterReceiver(this.receiver);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e);
|
||||
}
|
||||
@@ -157,21 +157,20 @@ public class NetworkManager extends Plugin {
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Updates the JavaScript side whenever the connection changes
|
||||
*
|
||||
*
|
||||
* @param info the current active network info
|
||||
* @return
|
||||
*/
|
||||
private void updateConnectionInfo(NetworkInfo info) {
|
||||
private void updateConnectionInfo(NetworkInfo info) {
|
||||
// send update to javascript "navigator.network.connection"
|
||||
sendUpdate(this.getConnectionInfo(info));
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get the latest network connection information
|
||||
*
|
||||
*
|
||||
* @param info the current active network info
|
||||
* @return a JSONObject that represents the network info
|
||||
*/
|
||||
@@ -188,24 +187,24 @@ public class NetworkManager extends Plugin {
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new plugin result and send it back to JavaScript
|
||||
*
|
||||
*
|
||||
* @param connection the network info to set as navigator.connection
|
||||
*/
|
||||
private void sendUpdate(String type) {
|
||||
PluginResult result = new PluginResult(PluginResult.Status.OK, type);
|
||||
result.setKeepCallback(true);
|
||||
this.success(result, this.connectionCallbackId);
|
||||
|
||||
|
||||
// Send to all plugins
|
||||
this.ctx.postMessage("networkconnection", type);
|
||||
webView.postMessage("networkconnection", type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine the type of connection
|
||||
*
|
||||
*
|
||||
* @param info the network info so we can determine connection type.
|
||||
* @return the type of mobile network we are on
|
||||
*/
|
||||
@@ -218,13 +217,13 @@ public class NetworkManager extends Plugin {
|
||||
}
|
||||
else if (type.toLowerCase().equals(MOBILE)) {
|
||||
type = info.getSubtypeName();
|
||||
if (type.toLowerCase().equals(GSM) ||
|
||||
if (type.toLowerCase().equals(GSM) ||
|
||||
type.toLowerCase().equals(GPRS) ||
|
||||
type.toLowerCase().equals(EDGE)) {
|
||||
return TYPE_2G;
|
||||
}
|
||||
else if (type.toLowerCase().startsWith(CDMA) ||
|
||||
type.toLowerCase().equals(UMTS) ||
|
||||
else if (type.toLowerCase().startsWith(CDMA) ||
|
||||
type.toLowerCase().equals(UMTS) ||
|
||||
type.toLowerCase().equals(ONEXRTT) ||
|
||||
type.toLowerCase().equals(EHRPD) ||
|
||||
type.toLowerCase().equals(HSUPA) ||
|
||||
@@ -232,13 +231,13 @@ public class NetworkManager extends Plugin {
|
||||
type.toLowerCase().equals(HSPA)) {
|
||||
return TYPE_3G;
|
||||
}
|
||||
else if (type.toLowerCase().equals(LTE) ||
|
||||
else if (type.toLowerCase().equals(LTE) ||
|
||||
type.toLowerCase().equals(UMB) ||
|
||||
type.toLowerCase().equals(HSPA_PLUS)) {
|
||||
return TYPE_4G;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return TYPE_NONE;
|
||||
}
|
||||
|
||||
@@ -36,331 +36,331 @@ import android.os.Vibrator;
|
||||
* This class provides access to notifications on the device.
|
||||
*/
|
||||
public class Notification extends Plugin {
|
||||
|
||||
public int confirmResult = -1;
|
||||
public ProgressDialog spinnerDialog = null;
|
||||
public ProgressDialog progressDialog = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public Notification() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("beep")) {
|
||||
this.beep(args.getLong(0));
|
||||
}
|
||||
else if (action.equals("vibrate")) {
|
||||
this.vibrate(args.getLong(0));
|
||||
}
|
||||
else if (action.equals("alert")) {
|
||||
this.alert(args.getString(0),args.getString(1),args.getString(2), callbackId);
|
||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
r.setKeepCallback(true);
|
||||
return r;
|
||||
}
|
||||
else if (action.equals("confirm")) {
|
||||
this.confirm(args.getString(0),args.getString(1),args.getString(2), callbackId);
|
||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
r.setKeepCallback(true);
|
||||
return r;
|
||||
}
|
||||
else if (action.equals("activityStart")) {
|
||||
this.activityStart(args.getString(0),args.getString(1));
|
||||
}
|
||||
else if (action.equals("activityStop")) {
|
||||
this.activityStop();
|
||||
}
|
||||
else if (action.equals("progressStart")) {
|
||||
this.progressStart(args.getString(0),args.getString(1));
|
||||
}
|
||||
else if (action.equals("progressValue")) {
|
||||
this.progressValue(args.getInt(0));
|
||||
}
|
||||
else if (action.equals("progressStop")) {
|
||||
this.progressStop();
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
public int confirmResult = -1;
|
||||
public ProgressDialog spinnerDialog = null;
|
||||
public ProgressDialog progressDialog = null;
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
if (action.equals("alert")) {
|
||||
return true;
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public Notification() {
|
||||
}
|
||||
else if (action.equals("confirm")) {
|
||||
return true;
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
if (action.equals("beep")) {
|
||||
this.beep(args.getLong(0));
|
||||
}
|
||||
else if (action.equals("vibrate")) {
|
||||
this.vibrate(args.getLong(0));
|
||||
}
|
||||
else if (action.equals("alert")) {
|
||||
this.alert(args.getString(0), args.getString(1), args.getString(2), callbackId);
|
||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
r.setKeepCallback(true);
|
||||
return r;
|
||||
}
|
||||
else if (action.equals("confirm")) {
|
||||
this.confirm(args.getString(0), args.getString(1), args.getString(2), callbackId);
|
||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||
r.setKeepCallback(true);
|
||||
return r;
|
||||
}
|
||||
else if (action.equals("activityStart")) {
|
||||
this.activityStart(args.getString(0), args.getString(1));
|
||||
}
|
||||
else if (action.equals("activityStop")) {
|
||||
this.activityStop();
|
||||
}
|
||||
else if (action.equals("progressStart")) {
|
||||
this.progressStart(args.getString(0), args.getString(1));
|
||||
}
|
||||
else if (action.equals("progressValue")) {
|
||||
this.progressValue(args.getInt(0));
|
||||
}
|
||||
else if (action.equals("progressStop")) {
|
||||
this.progressStop();
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
else if (action.equals("activityStart")) {
|
||||
return true;
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
if (action.equals("alert")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("confirm")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("activityStart")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("activityStop")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("progressStart")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("progressValue")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("progressStop")) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (action.equals("activityStop")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("progressStart")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("progressValue")) {
|
||||
return true;
|
||||
}
|
||||
else if (action.equals("progressStop")) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Beep plays the default notification ringtone.
|
||||
*
|
||||
* @param count Number of times to play notification
|
||||
*/
|
||||
public void beep(long count) {
|
||||
Uri ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
|
||||
Ringtone notification = RingtoneManager.getRingtone(this.ctx.getContext(), ringtone);
|
||||
|
||||
// If phone is not set to silent mode
|
||||
if (notification != null) {
|
||||
for (long i = 0; i < count; ++i) {
|
||||
notification.play();
|
||||
long timeout = 5000;
|
||||
while (notification.isPlaying() && (timeout > 0)) {
|
||||
timeout = timeout - 100;
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
/**
|
||||
* Beep plays the default notification ringtone.
|
||||
*
|
||||
* @param count Number of times to play notification
|
||||
*/
|
||||
public void beep(long count) {
|
||||
Uri ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
|
||||
Ringtone notification = RingtoneManager.getRingtone(this.cordova.getActivity().getBaseContext(), ringtone);
|
||||
|
||||
// If phone is not set to silent mode
|
||||
if (notification != null) {
|
||||
for (long i = 0; i < count; ++i) {
|
||||
notification.play();
|
||||
long timeout = 5000;
|
||||
while (notification.isPlaying() && (timeout > 0)) {
|
||||
timeout = timeout - 100;
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vibrates the device for the specified amount of time.
|
||||
*
|
||||
* @param time Time to vibrate in ms.
|
||||
*/
|
||||
public void vibrate(long time){
|
||||
|
||||
/**
|
||||
* Vibrates the device for the specified amount of time.
|
||||
*
|
||||
* @param time Time to vibrate in ms.
|
||||
*/
|
||||
public void vibrate(long time) {
|
||||
// Start the vibration, 0 defaults to half a second.
|
||||
if (time == 0) {
|
||||
time = 500;
|
||||
}
|
||||
Vibrator vibrator = (Vibrator) this.ctx.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
if (time == 0) {
|
||||
time = 500;
|
||||
}
|
||||
Vibrator vibrator = (Vibrator) this.cordova.getActivity().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
vibrator.vibrate(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and shows a native Android alert with given Strings
|
||||
* @param message The message the alert should display
|
||||
* @param title The title of the alert
|
||||
* @param buttonLabel The label of the button
|
||||
* @param callbackId The callback id
|
||||
*/
|
||||
public synchronized void alert(final String message, final String title, final String buttonLabel, final String callbackId) {
|
||||
|
||||
final CordovaInterface ctx = this.ctx;
|
||||
final Notification notification = this;
|
||||
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(ctx.getContext());
|
||||
dlg.setMessage(message);
|
||||
dlg.setTitle(title);
|
||||
dlg.setCancelable(false);
|
||||
dlg.setPositiveButton(buttonLabel,
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
notification.success(new PluginResult(PluginResult.Status.OK, 0), callbackId);
|
||||
}
|
||||
});
|
||||
dlg.create();
|
||||
dlg.show();
|
||||
};
|
||||
};
|
||||
this.ctx.runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and shows a native Android confirm dialog with given title, message, buttons.
|
||||
* This dialog only shows up to 3 buttons. Any labels after that will be ignored.
|
||||
* The index of the button pressed will be returned to the JavaScript callback identified by callbackId.
|
||||
*
|
||||
* @param message The message the dialog should display
|
||||
* @param title The title of the dialog
|
||||
* @param buttonLabels A comma separated list of button labels (Up to 3 buttons)
|
||||
* @param callbackId The callback id
|
||||
*/
|
||||
public synchronized void confirm(final String message, final String title, String buttonLabels, final String callbackId) {
|
||||
|
||||
final CordovaInterface ctx = this.ctx;
|
||||
final Notification notification = this;
|
||||
final String[] fButtons = buttonLabels.split(",");
|
||||
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(ctx.getContext());
|
||||
dlg.setMessage(message);
|
||||
dlg.setTitle(title);
|
||||
dlg.setCancelable(false);
|
||||
|
||||
// First button
|
||||
if (fButtons.length > 0) {
|
||||
dlg.setNegativeButton(fButtons[0],
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
notification.success(new PluginResult(PluginResult.Status.OK, 1), callbackId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Second button
|
||||
if (fButtons.length > 1) {
|
||||
dlg.setNeutralButton(fButtons[1],
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
notification.success(new PluginResult(PluginResult.Status.OK, 2), callbackId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Third button
|
||||
if (fButtons.length > 2) {
|
||||
dlg.setPositiveButton(fButtons[2],
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
notification.success(new PluginResult(PluginResult.Status.OK, 3), callbackId);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
dlg.create();
|
||||
dlg.show();
|
||||
};
|
||||
};
|
||||
this.ctx.runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the spinner.
|
||||
*
|
||||
* @param title Title of the dialog
|
||||
* @param message The message of the dialog
|
||||
*/
|
||||
public synchronized void activityStart(final String title, final String message) {
|
||||
if (this.spinnerDialog != null) {
|
||||
this.spinnerDialog.dismiss();
|
||||
this.spinnerDialog = null;
|
||||
}
|
||||
final Notification notification = this;
|
||||
final CordovaInterface ctx = this.ctx;
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
notification.spinnerDialog = ProgressDialog.show(ctx.getContext(), title , message, true, true,
|
||||
new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
notification.spinnerDialog = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
this.ctx.runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop spinner.
|
||||
*/
|
||||
public synchronized void activityStop() {
|
||||
if (this.spinnerDialog != null) {
|
||||
this.spinnerDialog.dismiss();
|
||||
this.spinnerDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the progress dialog.
|
||||
*
|
||||
* @param title Title of the dialog
|
||||
* @param message The message of the dialog
|
||||
*/
|
||||
public synchronized void progressStart(final String title, final String message) {
|
||||
if (this.progressDialog != null) {
|
||||
this.progressDialog.dismiss();
|
||||
this.progressDialog = null;
|
||||
/**
|
||||
* Builds and shows a native Android alert with given Strings
|
||||
* @param message The message the alert should display
|
||||
* @param title The title of the alert
|
||||
* @param buttonLabel The label of the button
|
||||
* @param callbackId The callback id
|
||||
*/
|
||||
public synchronized void alert(final String message, final String title, final String buttonLabel, final String callbackId) {
|
||||
|
||||
final CordovaInterface cordova = this.cordova;
|
||||
final Notification notification = this;
|
||||
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
|
||||
dlg.setMessage(message);
|
||||
dlg.setTitle(title);
|
||||
dlg.setCancelable(false);
|
||||
dlg.setPositiveButton(buttonLabel,
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
notification.success(new PluginResult(PluginResult.Status.OK, 0), callbackId);
|
||||
}
|
||||
});
|
||||
dlg.create();
|
||||
dlg.show();
|
||||
};
|
||||
};
|
||||
this.cordova.getActivity().runOnUiThread(runnable);
|
||||
}
|
||||
final Notification notification = this;
|
||||
final CordovaInterface ctx = this.ctx;
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
notification.progressDialog = new ProgressDialog(ctx.getContext());
|
||||
notification.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
notification.progressDialog.setTitle(title);
|
||||
notification.progressDialog.setMessage(message);
|
||||
notification.progressDialog.setCancelable(true);
|
||||
notification.progressDialog.setMax(100);
|
||||
notification.progressDialog.setProgress(0);
|
||||
notification.progressDialog.setOnCancelListener(
|
||||
new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
notification.progressDialog = null;
|
||||
|
||||
/**
|
||||
* Builds and shows a native Android confirm dialog with given title, message, buttons.
|
||||
* This dialog only shows up to 3 buttons. Any labels after that will be ignored.
|
||||
* The index of the button pressed will be returned to the JavaScript callback identified by callbackId.
|
||||
*
|
||||
* @param message The message the dialog should display
|
||||
* @param title The title of the dialog
|
||||
* @param buttonLabels A comma separated list of button labels (Up to 3 buttons)
|
||||
* @param callbackId The callback id
|
||||
*/
|
||||
public synchronized void confirm(final String message, final String title, String buttonLabels, final String callbackId) {
|
||||
|
||||
final CordovaInterface cordova = this.cordova;
|
||||
final Notification notification = this;
|
||||
final String[] fButtons = buttonLabels.split(",");
|
||||
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
|
||||
dlg.setMessage(message);
|
||||
dlg.setTitle(title);
|
||||
dlg.setCancelable(false);
|
||||
|
||||
// First button
|
||||
if (fButtons.length > 0) {
|
||||
dlg.setNegativeButton(fButtons[0],
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
notification.success(new PluginResult(PluginResult.Status.OK, 1), callbackId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Second button
|
||||
if (fButtons.length > 1) {
|
||||
dlg.setNeutralButton(fButtons[1],
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
notification.success(new PluginResult(PluginResult.Status.OK, 2), callbackId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Third button
|
||||
if (fButtons.length > 2) {
|
||||
dlg.setPositiveButton(fButtons[2],
|
||||
new AlertDialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
notification.success(new PluginResult(PluginResult.Status.OK, 3), callbackId);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
dlg.create();
|
||||
dlg.show();
|
||||
};
|
||||
};
|
||||
this.cordova.getActivity().runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the spinner.
|
||||
*
|
||||
* @param title Title of the dialog
|
||||
* @param message The message of the dialog
|
||||
*/
|
||||
public synchronized void activityStart(final String title, final String message) {
|
||||
if (this.spinnerDialog != null) {
|
||||
this.spinnerDialog.dismiss();
|
||||
this.spinnerDialog = null;
|
||||
}
|
||||
final Notification notification = this;
|
||||
final CordovaInterface cordova = this.cordova;
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
notification.spinnerDialog = ProgressDialog.show(cordova.getActivity(), title, message, true, true,
|
||||
new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
notification.spinnerDialog = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
notification.progressDialog.show();
|
||||
}
|
||||
};
|
||||
this.ctx.runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value of progress bar.
|
||||
*
|
||||
* @param value 0-100
|
||||
*/
|
||||
public synchronized void progressValue(int value) {
|
||||
if (this.progressDialog != null) {
|
||||
this.progressDialog.setProgress(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop progress dialog.
|
||||
*/
|
||||
public synchronized void progressStop() {
|
||||
if (this.progressDialog != null) {
|
||||
this.progressDialog.dismiss();
|
||||
this.progressDialog = null;
|
||||
};
|
||||
this.cordova.getActivity().runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop spinner.
|
||||
*/
|
||||
public synchronized void activityStop() {
|
||||
if (this.spinnerDialog != null) {
|
||||
this.spinnerDialog.dismiss();
|
||||
this.spinnerDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the progress dialog.
|
||||
*
|
||||
* @param title Title of the dialog
|
||||
* @param message The message of the dialog
|
||||
*/
|
||||
public synchronized void progressStart(final String title, final String message) {
|
||||
if (this.progressDialog != null) {
|
||||
this.progressDialog.dismiss();
|
||||
this.progressDialog = null;
|
||||
}
|
||||
final Notification notification = this;
|
||||
final CordovaInterface cordova = this.cordova;
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
notification.progressDialog = new ProgressDialog(cordova.getActivity());
|
||||
notification.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
notification.progressDialog.setTitle(title);
|
||||
notification.progressDialog.setMessage(message);
|
||||
notification.progressDialog.setCancelable(true);
|
||||
notification.progressDialog.setMax(100);
|
||||
notification.progressDialog.setProgress(0);
|
||||
notification.progressDialog.setOnCancelListener(
|
||||
new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
notification.progressDialog = null;
|
||||
}
|
||||
});
|
||||
notification.progressDialog.show();
|
||||
}
|
||||
};
|
||||
this.cordova.getActivity().runOnUiThread(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value of progress bar.
|
||||
*
|
||||
* @param value 0-100
|
||||
*/
|
||||
public synchronized void progressValue(int value) {
|
||||
if (this.progressDialog != null) {
|
||||
this.progressDialog.setProgress(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop progress dialog.
|
||||
*/
|
||||
public synchronized void progressStop() {
|
||||
if (this.progressDialog != null) {
|
||||
this.progressDialog.dismiss();
|
||||
this.progressDialog = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.apache.cordova.PreferenceNode;
|
||||
|
||||
|
||||
public class PreferenceSet {
|
||||
private HashSet<PreferenceNode> innerSet;
|
||||
|
||||
public PreferenceSet() {
|
||||
this.innerSet = new HashSet<PreferenceNode>();
|
||||
}
|
||||
|
||||
public void add(PreferenceNode node) {
|
||||
this.innerSet.add(node);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.innerSet.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.innerSet.clear();
|
||||
}
|
||||
|
||||
public String pref(String prefName) {
|
||||
for (PreferenceNode n : innerSet)
|
||||
if (prefName.equals(n.name))
|
||||
return n.value;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean prefMatches(String prefName, String prefValue) {
|
||||
String value = pref(prefName);
|
||||
|
||||
if (value == null) {
|
||||
return false;
|
||||
} else {
|
||||
return value.equals(prefValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,9 @@ public class SplashScreen extends Plugin {
|
||||
String result = "";
|
||||
|
||||
if (action.equals("hide")) {
|
||||
((DroidGap)this.ctx).removeSplashScreen();
|
||||
this.webView.postMessage("splashscreen", "hide");
|
||||
} else if (action.equals("show")){
|
||||
this.webView.postMessage("splashscreen", "show");
|
||||
}
|
||||
else {
|
||||
status = PluginResult.Status.INVALID_ACTION;
|
||||
|
||||
@@ -18,18 +18,15 @@
|
||||
*/
|
||||
package org.apache.cordova;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class StandAlone extends DroidGap {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
super.loadUrl("file:///android_asset/www/index.html");
|
||||
}
|
||||
|
||||
|
||||
super.loadUrl("file:///android_asset/www/index.html");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,209 +31,209 @@ import android.database.Cursor;
|
||||
import android.database.sqlite.*;
|
||||
|
||||
/**
|
||||
* This class implements the HTML5 database support to work around a bug for
|
||||
* Android 3.0 devices. It is not used for other versions of Android, since
|
||||
* This class implements the HTML5 database support to work around a bug for
|
||||
* Android 3.0 devices. It is not used for other versions of Android, since
|
||||
* HTML5 database is built in to the browser.
|
||||
*/
|
||||
public class Storage extends Plugin {
|
||||
|
||||
// Data Definition Language
|
||||
private static final String ALTER = "alter";
|
||||
private static final String CREATE = "create";
|
||||
private static final String DROP = "drop";
|
||||
private static final String TRUNCATE = "truncate";
|
||||
|
||||
SQLiteDatabase myDb = null; // Database object
|
||||
String path = null; // Database path
|
||||
String dbName = null; // Database name
|
||||
// Data Definition Language
|
||||
private static final String ALTER = "alter";
|
||||
private static final String CREATE = "create";
|
||||
private static final String DROP = "drop";
|
||||
private static final String TRUNCATE = "truncate";
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public Storage() {
|
||||
}
|
||||
SQLiteDatabase myDb = null; // Database object
|
||||
String path = null; // Database path
|
||||
String dbName = null; // Database name
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action
|
||||
* The action to execute.
|
||||
* @param args
|
||||
* JSONArry of arguments for the plugin.
|
||||
* @param callbackId
|
||||
* The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public Storage() {
|
||||
}
|
||||
|
||||
try {
|
||||
if (action.equals("openDatabase")) {
|
||||
this.openDatabase(args.getString(0), args.getString(1),
|
||||
args.getString(2), args.getLong(3));
|
||||
} else if (action.equals("executeSql")) {
|
||||
String[] s = null;
|
||||
if (args.isNull(1)) {
|
||||
s = new String[0];
|
||||
} else {
|
||||
JSONArray a = args.getJSONArray(1);
|
||||
int len = a.length();
|
||||
s = new String[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
s[i] = a.getString(i);
|
||||
}
|
||||
}
|
||||
this.executeSql(args.getString(0), s, args.getString(2));
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action
|
||||
* The action to execute.
|
||||
* @param args
|
||||
* JSONArry of arguments for the plugin.
|
||||
* @param callbackId
|
||||
* The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run
|
||||
* synchronously.
|
||||
*
|
||||
* @param action
|
||||
* The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
if (action.equals("openDatabase")) {
|
||||
this.openDatabase(args.getString(0), args.getString(1),
|
||||
args.getString(2), args.getLong(3));
|
||||
} else if (action.equals("executeSql")) {
|
||||
String[] s = null;
|
||||
if (args.isNull(1)) {
|
||||
s = new String[0];
|
||||
} else {
|
||||
JSONArray a = args.getJSONArray(1);
|
||||
int len = a.length();
|
||||
s = new String[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
s[i] = a.getString(i);
|
||||
}
|
||||
}
|
||||
this.executeSql(args.getString(0), s, args.getString(2));
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
} catch (JSONException e) {
|
||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up and close database.
|
||||
*/
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (this.myDb != null) {
|
||||
this.myDb.close();
|
||||
this.myDb = null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run
|
||||
* synchronously.
|
||||
*
|
||||
* @param action
|
||||
* The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
// --------------------------------------------------------------------------
|
||||
/**
|
||||
* Clean up and close database.
|
||||
*/
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (this.myDb != null) {
|
||||
this.myDb.close();
|
||||
this.myDb = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open database.
|
||||
*
|
||||
* @param db
|
||||
* The name of the database
|
||||
* @param version
|
||||
* The version
|
||||
* @param display_name
|
||||
* The display name
|
||||
* @param size
|
||||
* The size in bytes
|
||||
*/
|
||||
public void openDatabase(String db, String version, String display_name,
|
||||
long size) {
|
||||
// --------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// If database is open, then close it
|
||||
if (this.myDb != null) {
|
||||
this.myDb.close();
|
||||
}
|
||||
/**
|
||||
* Open database.
|
||||
*
|
||||
* @param db
|
||||
* The name of the database
|
||||
* @param version
|
||||
* The version
|
||||
* @param display_name
|
||||
* The display name
|
||||
* @param size
|
||||
* The size in bytes
|
||||
*/
|
||||
public void openDatabase(String db, String version, String display_name,
|
||||
long size) {
|
||||
|
||||
// If no database path, generate from application package
|
||||
if (this.path == null) {
|
||||
this.path = this.ctx.getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
|
||||
}
|
||||
// If database is open, then close it
|
||||
if (this.myDb != null) {
|
||||
this.myDb.close();
|
||||
}
|
||||
|
||||
this.dbName = this.path + File.pathSeparator + db + ".db";
|
||||
this.myDb = SQLiteDatabase.openOrCreateDatabase(this.dbName, null);
|
||||
}
|
||||
// If no database path, generate from application package
|
||||
if (this.path == null) {
|
||||
this.path = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute SQL statement.
|
||||
*
|
||||
* @param query
|
||||
* The SQL query
|
||||
* @param params
|
||||
* Parameters for the query
|
||||
* @param tx_id
|
||||
* Transaction id
|
||||
*/
|
||||
public void executeSql(String query, String[] params, String tx_id) {
|
||||
try {
|
||||
if (isDDL(query)) {
|
||||
this.myDb.execSQL(query);
|
||||
this.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', '');");
|
||||
}
|
||||
else {
|
||||
Cursor myCursor = this.myDb.rawQuery(query, params);
|
||||
this.processResults(myCursor, tx_id);
|
||||
myCursor.close();
|
||||
}
|
||||
}
|
||||
catch (SQLiteException ex) {
|
||||
ex.printStackTrace();
|
||||
System.out.println("Storage.executeSql(): Error=" + ex.getMessage());
|
||||
|
||||
// Send error message back to JavaScript
|
||||
this.sendJavascript("cordova.require('cordova/plugin/android/storage').failQuery('" + ex.getMessage() + "','" + tx_id + "');");
|
||||
}
|
||||
}
|
||||
this.dbName = this.path + File.pathSeparator + db + ".db";
|
||||
this.myDb = SQLiteDatabase.openOrCreateDatabase(this.dbName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see the the query is a Data Definintion command
|
||||
*
|
||||
* @param query to be executed
|
||||
* @return true if it is a DDL command, false otherwise
|
||||
*/
|
||||
private boolean isDDL(String query) {
|
||||
String cmd = query.toLowerCase();
|
||||
if (cmd.startsWith(DROP) || cmd.startsWith(CREATE) || cmd.startsWith(ALTER) || cmd.startsWith(TRUNCATE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Execute SQL statement.
|
||||
*
|
||||
* @param query
|
||||
* The SQL query
|
||||
* @param params
|
||||
* Parameters for the query
|
||||
* @param tx_id
|
||||
* Transaction id
|
||||
*/
|
||||
public void executeSql(String query, String[] params, String tx_id) {
|
||||
try {
|
||||
if (isDDL(query)) {
|
||||
this.myDb.execSQL(query);
|
||||
this.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', '');");
|
||||
}
|
||||
else {
|
||||
Cursor myCursor = this.myDb.rawQuery(query, params);
|
||||
this.processResults(myCursor, tx_id);
|
||||
myCursor.close();
|
||||
}
|
||||
}
|
||||
catch (SQLiteException ex) {
|
||||
ex.printStackTrace();
|
||||
System.out.println("Storage.executeSql(): Error=" + ex.getMessage());
|
||||
|
||||
/**
|
||||
* Process query results.
|
||||
*
|
||||
* @param cur
|
||||
* Cursor into query results
|
||||
* @param tx_id
|
||||
* Transaction id
|
||||
*/
|
||||
public void processResults(Cursor cur, String tx_id) {
|
||||
// Send error message back to JavaScript
|
||||
this.sendJavascript("cordova.require('cordova/plugin/android/storage').failQuery('" + ex.getMessage() + "','" + tx_id + "');");
|
||||
}
|
||||
}
|
||||
|
||||
String result = "[]";
|
||||
// If query result has rows
|
||||
/**
|
||||
* Checks to see the the query is a Data Definintion command
|
||||
*
|
||||
* @param query to be executed
|
||||
* @return true if it is a DDL command, false otherwise
|
||||
*/
|
||||
private boolean isDDL(String query) {
|
||||
String cmd = query.toLowerCase();
|
||||
if (cmd.startsWith(DROP) || cmd.startsWith(CREATE) || cmd.startsWith(ALTER) || cmd.startsWith(TRUNCATE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cur.moveToFirst()) {
|
||||
JSONArray fullresult = new JSONArray();
|
||||
String key = "";
|
||||
String value = "";
|
||||
int colCount = cur.getColumnCount();
|
||||
/**
|
||||
* Process query results.
|
||||
*
|
||||
* @param cur
|
||||
* Cursor into query results
|
||||
* @param tx_id
|
||||
* Transaction id
|
||||
*/
|
||||
public void processResults(Cursor cur, String tx_id) {
|
||||
|
||||
// Build up JSON result object for each row
|
||||
do {
|
||||
JSONObject row = new JSONObject();
|
||||
try {
|
||||
for (int i = 0; i < colCount; ++i) {
|
||||
key = cur.getColumnName(i);
|
||||
value = cur.getString(i);
|
||||
row.put(key, value);
|
||||
}
|
||||
fullresult.put(row);
|
||||
String result = "[]";
|
||||
// If query result has rows
|
||||
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (cur.moveToFirst()) {
|
||||
JSONArray fullresult = new JSONArray();
|
||||
String key = "";
|
||||
String value = "";
|
||||
int colCount = cur.getColumnCount();
|
||||
|
||||
} while (cur.moveToNext());
|
||||
// Build up JSON result object for each row
|
||||
do {
|
||||
JSONObject row = new JSONObject();
|
||||
try {
|
||||
for (int i = 0; i < colCount; ++i) {
|
||||
key = cur.getColumnName(i);
|
||||
value = cur.getString(i);
|
||||
row.put(key, value);
|
||||
}
|
||||
fullresult.put(row);
|
||||
|
||||
result = fullresult.toString();
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Let JavaScript know that there are no more rows
|
||||
this.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', " + result + ");");
|
||||
}
|
||||
} while (cur.moveToNext());
|
||||
|
||||
result = fullresult.toString();
|
||||
}
|
||||
|
||||
// Let JavaScript know that there are no more rows
|
||||
this.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', " + result + ");");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.apache.cordova.api.Plugin;
|
||||
import org.apache.cordova.api.PluginResult;
|
||||
import org.json.JSONArray;
|
||||
|
||||
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
@@ -33,80 +32,81 @@ import android.hardware.SensorManager;
|
||||
import android.content.Context;
|
||||
|
||||
public class TempListener extends Plugin implements SensorEventListener {
|
||||
|
||||
Sensor mSensor;
|
||||
private SensorManager sensorManager;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public TempListener() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
public void setContext(CordovaInterface ctx) {
|
||||
super.setContext(ctx);
|
||||
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
Sensor mSensor;
|
||||
private SensorManager sensorManager;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public TempListener() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context of the Command. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param cordova The context of the main Activity.
|
||||
*/
|
||||
public void setContext(CordovaInterface cordova) {
|
||||
super.setContext(cordova);
|
||||
this.sensorManager = (SensorManager) cordova.getActivity().getSystemService(Context.SENSOR_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
if (action.equals("start")) {
|
||||
this.start();
|
||||
}
|
||||
else if (action.equals("stop")) {
|
||||
this.stop();
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
||||
PluginResult.Status status = PluginResult.Status.OK;
|
||||
String result = "";
|
||||
|
||||
if (action.equals("start")) {
|
||||
this.start();
|
||||
}
|
||||
else if (action.equals("stop")) {
|
||||
this.stop();
|
||||
}
|
||||
return new PluginResult(status, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by AccelBroker when listener is to be shut down.
|
||||
* Stop listener.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
this.stop();
|
||||
this.stop();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
public void start() {
|
||||
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_TEMPERATURE);
|
||||
if (list.size() > 0) {
|
||||
this.mSensor = list.get(0);
|
||||
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
this.sensorManager.unregisterListener(this);
|
||||
}
|
||||
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
public void start() {
|
||||
@SuppressWarnings("deprecation")
|
||||
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_TEMPERATURE);
|
||||
if (list.size() > 0) {
|
||||
this.mSensor = list.get(0);
|
||||
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
// We want to know what temp this is.
|
||||
float temp = event.values[0];
|
||||
this.sendJavascript("gotTemp(" + temp + ");");
|
||||
}
|
||||
public void stop() {
|
||||
this.sensorManager.unregisterListener(this);
|
||||
}
|
||||
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
// We want to know what temp this is.
|
||||
float temp = event.values[0];
|
||||
this.sendJavascript("gotTemp(" + temp + ");");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,21 +18,8 @@
|
||||
*/
|
||||
package org.apache.cordova.api;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.hardware.SensorManager;
|
||||
import android.net.Uri;
|
||||
|
||||
|
||||
/**
|
||||
* The Cordova activity abstract class that is extended by DroidGap.
|
||||
@@ -41,107 +28,40 @@ import android.net.Uri;
|
||||
public interface CordovaInterface {
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Add services to res/xml/plugins.xml instead.
|
||||
*
|
||||
* Add a class that implements a service.
|
||||
*
|
||||
* @param serviceType
|
||||
* @param className
|
||||
*/
|
||||
@Deprecated
|
||||
abstract public void addService(String serviceType, String className);
|
||||
|
||||
/**
|
||||
* Send JavaScript statement back to JavaScript.
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
abstract public void sendJavascript(String statement);
|
||||
|
||||
/**
|
||||
* Launch an activity for which you would like a result when it finished. When this activity exits,
|
||||
* Launch an activity for which you would like a result when it finished. When this activity exits,
|
||||
* your onActivityResult() method will be called.
|
||||
*
|
||||
* @param command The command object
|
||||
* @param intent The intent to start
|
||||
* @param requestCode The request code that is passed to callback to identify the activity
|
||||
*
|
||||
* @param command The command object
|
||||
* @param intent The intent to start
|
||||
* @param requestCode The request code that is passed to callback to identify the activity
|
||||
*/
|
||||
abstract public void startActivityForResult(IPlugin command, Intent intent, int requestCode);
|
||||
|
||||
/**
|
||||
* Launch an activity for which you would not like a result when it finished.
|
||||
*
|
||||
* @param intent The intent to start
|
||||
*/
|
||||
abstract public void startActivity(Intent intent);
|
||||
|
||||
|
||||
/**
|
||||
* Set the plugin to be called when a sub-activity exits.
|
||||
*
|
||||
* @param plugin The plugin on which onActivityResult is to be called
|
||||
*
|
||||
* @param plugin The plugin on which onActivityResult is to be called
|
||||
*/
|
||||
abstract public void setActivityResultCallback(IPlugin plugin);
|
||||
|
||||
|
||||
/**
|
||||
* Load the specified URL in the Cordova webview.
|
||||
*
|
||||
* @param url The URL to load.
|
||||
* Get the Android activity.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
abstract public void loadUrl(String url);
|
||||
|
||||
/**
|
||||
* Send a message to all plugins.
|
||||
*
|
||||
* @param id The message id
|
||||
* @param data The message data
|
||||
*/
|
||||
abstract public void postMessage(String id, Object data);
|
||||
|
||||
|
||||
public abstract Resources getResources();
|
||||
|
||||
public abstract String getPackageName();
|
||||
|
||||
public abstract Object getSystemService(String service);
|
||||
|
||||
public abstract Context getContext();
|
||||
|
||||
public abstract Context getBaseContext();
|
||||
|
||||
public abstract Intent registerReceiver(BroadcastReceiver receiver,
|
||||
IntentFilter intentFilter);
|
||||
|
||||
public abstract ContentResolver getContentResolver();
|
||||
|
||||
public abstract void unregisterReceiver(BroadcastReceiver receiver);
|
||||
|
||||
public abstract Cursor managedQuery(Uri uri, String[] projection, String selection,
|
||||
String[] selectionArgs, String sortOrder);
|
||||
|
||||
public abstract void runOnUiThread(Runnable runnable);
|
||||
|
||||
public abstract AssetManager getAssets();
|
||||
|
||||
public abstract void clearCache();
|
||||
|
||||
public abstract void clearHistory();
|
||||
|
||||
public abstract boolean backHistory();
|
||||
|
||||
//public abstract void addWhiteListEntry(String origin, boolean subdomains);
|
||||
|
||||
public abstract void bindBackButton(boolean override);
|
||||
|
||||
public abstract boolean isBackButtonBound();
|
||||
public abstract Activity getActivity();
|
||||
|
||||
@Deprecated
|
||||
public abstract void cancelLoadUrl();
|
||||
|
||||
public abstract void showWebPage(String url, boolean openExternal,
|
||||
boolean clearHistory, HashMap<String, Object> params);
|
||||
/**
|
||||
* Called when a message is sent to plugin.
|
||||
*
|
||||
* @param id The message id
|
||||
* @param data The message data
|
||||
* @return Object or null
|
||||
*/
|
||||
public Object onMessage(String id, Object data);
|
||||
|
||||
public abstract Context getApplicationContext();
|
||||
|
||||
public abstract boolean isUrlWhiteListed(String source);
|
||||
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
*/
|
||||
package org.apache.cordova.api;
|
||||
|
||||
import org.apache.cordova.CordovaWebView;
|
||||
import org.json.JSONArray;
|
||||
|
||||
//import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.webkit.WebView;
|
||||
|
||||
/**
|
||||
* Plugin interface must be implemented by any plugin classes.
|
||||
@@ -28,78 +30,79 @@ import android.webkit.WebView;
|
||||
* The execute method is called by the PluginManager.
|
||||
*/
|
||||
public interface IPlugin {
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
PluginResult execute(String action, JSONArray args, String callbackId);
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action);
|
||||
|
||||
/**
|
||||
* Sets the context of the Plugin. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
void setContext(CordovaInterface ctx);
|
||||
|
||||
/**
|
||||
* Sets the main View of the application, this is the WebView within which
|
||||
* a Cordova app runs.
|
||||
*
|
||||
* @param webView The Cordova WebView
|
||||
*/
|
||||
void setView(WebView webView);
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity.
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArry of arguments for the plugin.
|
||||
* @param callbackId The callback id used when calling back into JavaScript.
|
||||
* @return A PluginResult object with a status and message.
|
||||
*/
|
||||
PluginResult execute(String action, JSONArray args, String callbackId);
|
||||
|
||||
/**
|
||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
||||
*
|
||||
* @param action The action to execute
|
||||
* @return T=returns value
|
||||
*/
|
||||
public boolean isSynch(String action);
|
||||
|
||||
/**
|
||||
* Sets the context of the Plugin. This can then be used to do things like
|
||||
* get file paths associated with the Activity.
|
||||
*
|
||||
* @param ctx The context of the main Activity.
|
||||
*/
|
||||
void setContext(CordovaInterface ctx);
|
||||
|
||||
/**
|
||||
* Sets the main View of the application, this is the WebView within which
|
||||
* a Cordova app runs.
|
||||
*
|
||||
* @param webView The Cordova WebView
|
||||
*/
|
||||
void setView(CordovaWebView webView);
|
||||
|
||||
/**
|
||||
* Called when the system is about to start resuming a previous activity.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
void onPause(boolean multitasking);
|
||||
|
||||
/**
|
||||
* Called when the activity will start interacting with the user.
|
||||
*
|
||||
* Called when the activity will start interacting with the user.
|
||||
*
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
void onResume(boolean multitasking);
|
||||
|
||||
|
||||
/**
|
||||
* Called when the activity receives a new intent.
|
||||
* Called when the activity receives a new intent.
|
||||
*/
|
||||
void onNewIntent(Intent intent);
|
||||
|
||||
/**
|
||||
* The final call you receive before your activity is destroyed.
|
||||
* The final call you receive before your activity is destroyed.
|
||||
*/
|
||||
void onDestroy();
|
||||
|
||||
|
||||
/**
|
||||
* Called when a message is sent to plugin.
|
||||
*
|
||||
* Called when a message is sent to plugin.
|
||||
*
|
||||
* @param id The message id
|
||||
* @param data The message data
|
||||
* @return Object to stop propagation or null
|
||||
*/
|
||||
public void onMessage(String id, Object data);
|
||||
public Object onMessage(String id, Object data);
|
||||
|
||||
/**
|
||||
* Called when an activity you launched exits, giving you the requestCode you started it with,
|
||||
* the resultCode it returned, and any additional data from it.
|
||||
*
|
||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
||||
* the resultCode it returned, and any additional data from it.
|
||||
*
|
||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
||||
* allowing you to identify who this result came from.
|
||||
* @param resultCode The integer result code returned by the child activity through its setResult().
|
||||
* @param data An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
|
||||
@@ -108,7 +111,7 @@ public interface IPlugin {
|
||||
|
||||
/**
|
||||
* By specifying a <url-filter> in plugins.xml you can map a URL (using startsWith atm) to this method.
|
||||
*
|
||||
*
|
||||
* @param url The URL that is trying to be loaded in the Cordova webview.
|
||||
* @return Return true to prevent the URL from loading. Default is false.
|
||||
*/
|
||||
|
||||