Compare commits
613 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6efeb1471c | |||
| 01f062d2ba | |||
| 2a42c463d2 | |||
| 182843edf6 | |||
| 9a9d36e9d9 | |||
| 7d5249eea6 | |||
| f7910c41c3 | |||
| 3973f4f952 | |||
| 8a19769a47 | |||
| c0ee593c10 | |||
| c806451b8a | |||
| 00e5ff1964 | |||
| 432aec62a9 | |||
| 2c202b82d7 | |||
| a42dc08756 | |||
| 48f58110fe | |||
| 7b3724972b | |||
| 9ca2a16218 | |||
| f1e8400abf | |||
| 11e0ffa90a | |||
| 2ee4326a4d | |||
| 226e72ac18 | |||
| 65c78b8f3f | |||
| 6137c7ca06 | |||
| 5bebf11b37 | |||
| 68161d2714 | |||
| a6473cb826 | |||
| 0084c6f96a | |||
| a87825dbee | |||
| 3566154cd0 | |||
| 92d69e320f | |||
| 08a190ef5b | |||
| 98339ee5d8 | |||
| fa387fd758 | |||
| 54979f2fc4 | |||
| 538e90f23a | |||
| d9107bcac6 | |||
| 3f3a0b9140 | |||
| e1347e434e | |||
| 7657faa9c3 | |||
| 28ef765913 | |||
| d2f59391a2 | |||
| df90bdb350 | |||
| c416c77d7a | |||
| ce05a720d1 | |||
| 6c19a440f5 | |||
| f4612fdb5d | |||
| 04b9a0b09e | |||
| f93c438067 | |||
| e1d608443a | |||
| 9233c3a898 | |||
| dfa514334b | |||
| 5810a96e62 | |||
| 70473a80af | |||
| 525fd30cb2 | |||
| 5212cd4dcd | |||
| e95bde62a2 | |||
| 4fe73cf6ad | |||
| 78b2835da4 | |||
| f9a49efae9 | |||
| b9ddc9e678 | |||
| dc459c84a3 | |||
| 1d26239809 | |||
| e51b4897a3 | |||
| 81f283e56f | |||
| ccdd2fd2ca | |||
| 69f11a29e1 | |||
| cf494f3238 | |||
| d5895c635a | |||
| 2ac9873613 | |||
| eb59e76cde | |||
| d9db845b43 | |||
| e55327b064 | |||
| bdd5a4e053 | |||
| ac2e2c9a42 | |||
| 76f9d49e24 | |||
| 6ec8ab95fc | |||
| 9c98625610 | |||
| f270cde47d | |||
| 9de7efd072 | |||
| 7b81d317a0 | |||
| 876f975aa2 | |||
| 3c5815ac0f | |||
| 678ae2d684 | |||
| e4f8f44fb0 | |||
| 49566d29f8 | |||
| 7f4ee7b20a | |||
| 32526a8c16 | |||
| 71a7f72ab9 | |||
| 4d0824f4a4 | |||
| d56dd40d06 | |||
| 6aafd6dc3a | |||
| 011b512f28 | |||
| aa2d17e489 | |||
| 0eee2293dc | |||
| a2f35d2bda | |||
| 58f58d9ee8 | |||
| 412bb349ac | |||
| 652f15f893 | |||
| 8512ebb923 | |||
| f0ac173ec8 | |||
| bef0d47924 | |||
| cba0d59021 | |||
| 7d3afcab94 | |||
| 5f1cda07e7 | |||
| e11beade4b | |||
| 6a1e089b73 | |||
| 0aa98ac2da | |||
| f9ef38cc7a | |||
| a3a215a1ba | |||
| d3ee322d7c | |||
| 7ec20e7752 | |||
| 08dfb13dbf | |||
| 6a5cddd907 | |||
| dc5078306d | |||
| 1bc032853c | |||
| e562e4e7b9 | |||
| 0ffffa9029 | |||
| 0f2303e8d5 | |||
| 31f7f8149e | |||
| fe1f57c23f | |||
| 29a0b010da | |||
| 621e1163f8 | |||
| 17d64cfcbe | |||
| 7379d2135d | |||
| c55fd06b99 | |||
| d81727a08c | |||
| b582e1592a | |||
| dd8533a320 | |||
| d72a8cbf89 | |||
| fe0876ded6 | |||
| fa15763c5d | |||
| 205215d409 | |||
| 076bfcde87 | |||
| 10510484b5 | |||
| e1dea5b4d3 | |||
| 891f8d00cf | |||
| 0d409f0fe3 | |||
| 4e0c8982c9 | |||
| a741c66c97 | |||
| 3e6a7cbdf5 | |||
| 5d34aa0afe | |||
| 979ae94698 | |||
| 8d7b85b26a | |||
| 686977a986 | |||
| 9c6c782146 | |||
| ca9539b5b6 | |||
| ff25be8839 | |||
| d1ab1b59be | |||
| 05bc1865a6 | |||
| 6e6e0275ad | |||
| ec3c5b2ca2 | |||
| 5289d569b0 | |||
| 6f873ff6b5 | |||
| 467cbe972c | |||
| bfd1bfe9f0 | |||
| 3404a6c699 | |||
| 17a4b5155e | |||
| d406e2ed22 | |||
| 0bfc9935b2 | |||
| 64c6cbe303 | |||
| 2245db3e80 | |||
| 6f19a50c98 | |||
| c7ce9598a8 | |||
| afcdccf783 | |||
| 1bf12842ca | |||
| da8fbee256 | |||
| 4021f26e76 | |||
| 8eab8438cf | |||
| 1b4096b01d | |||
| 54caa6e438 | |||
| 486eb149f2 | |||
| faa034a205 | |||
| 2cd3ebc7a8 | |||
| 7e3af6c235 | |||
| dd4de16d1d | |||
| ba8577fa5f | |||
| 6192319f8c | |||
| fed368d553 | |||
| 20c885418e | |||
| 9318ee30bd | |||
| 8b6c9574df | |||
| 313148136a | |||
| 6e1fdc77ae | |||
| 2a9582ebb1 | |||
| dd1cd46719 | |||
| 9961d9e54d | |||
| 7eb12110d1 | |||
| 3d62744601 | |||
| 17af417235 | |||
| df9d314361 | |||
| 610e0c984a | |||
| 3688fca126 | |||
| 9bc89c784f | |||
| 79682f5d52 | |||
| c206ac0335 | |||
| 34840175f3 | |||
| 6312457425 | |||
| f71e664952 | |||
| 80d559f17e | |||
| 772aedc263 | |||
| 45d7c124c8 | |||
| 73abb20b3d | |||
| 0baf104a75 | |||
| 302d51cdfd | |||
| d3cbfd5467 | |||
| 9e3e7e1820 | |||
| 18893bf6cd | |||
| f53161d6f5 | |||
| 4c9a571106 | |||
| 365edcad16 | |||
| ae9047a708 | |||
| 9c0e58df8d | |||
| ee34f11c29 | |||
| 6ca6d88bff | |||
| 65a397fb63 | |||
| 0a669077fb | |||
| 451688a12e | |||
| d181d89dd2 | |||
| ac14b0d73b | |||
| 0f42c65792 | |||
| 37b3e980dc | |||
| eb49e011e2 | |||
| e0a73f72ee | |||
| e217ab28c5 | |||
| ca583865ea | |||
| 5e7efde311 | |||
| 2c7c13420b | |||
| ac4fc3e54e | |||
| 46db36a05e | |||
| 3d073be990 | |||
| 1bc49fe450 | |||
| 1f7fe9abcc | |||
| 5217abf57a | |||
| 2ecbde891a | |||
| bf7fc66646 | |||
| 5a94b38e2f | |||
| 1bc55f5937 | |||
| 04c9542f94 | |||
| 17e739f68a | |||
| 4f5515fde3 | |||
| ae3ba129ea | |||
| 6b92a0fff7 | |||
| d859bb8e67 | |||
| f12bbf71ed | |||
| b723beb545 | |||
| 47daaaf14f | |||
| 9ba5bae34d | |||
| dbfa2d7994 | |||
| 8134f86d1f | |||
| 5c60b09bf4 | |||
| 20a19d67d0 | |||
| 311a2f6023 | |||
| 59a3cf93e6 | |||
| a42f095cef | |||
| a29340523f | |||
| 5ad7a7c014 | |||
| c6fa7e4aad | |||
| d4b248fbe3 | |||
| 48881d081a | |||
| 331024414e | |||
| 9d0c5349bb | |||
| dc40d8afac | |||
| 005877b4b8 | |||
| 774d21747a | |||
| 12e5b39c05 | |||
| 4d5e452ece | |||
| 1ba3ecbef3 | |||
| db6695cb02 | |||
| b3f5e039f2 | |||
| c3e17fb185 | |||
| f7ae7fe43a | |||
| e07822350e | |||
| 07439ff99c | |||
| f111c245c1 | |||
| c3502da4a0 | |||
| 4012108d48 | |||
| 4a0605e09b | |||
| 250380d73e | |||
| b30f5d782d | |||
| b00cd9b557 | |||
| e11f8f646b | |||
| 92b1de8cf8 | |||
| bbafe53a2b | |||
| e239fd970f | |||
| 7fa4515c28 | |||
| b40eb0a454 | |||
| 5e3e9ddb8e | |||
| a9a5284a67 | |||
| afe504dbbf | |||
| 0c484ddcf7 | |||
| 8d0e80620a | |||
| 1d28506b09 | |||
| 1b33dbe2ae | |||
| 80654c059d | |||
| 999c548e6e | |||
| e42913ae8a | |||
| ee07cbecba | |||
| fffaa9bced | |||
| 6195b2c99d | |||
| 06aafc96c9 | |||
| 2dc0727e36 | |||
| a219feaa60 | |||
| f3a09da340 | |||
| 946e345a3f | |||
| 6cb8d11b22 | |||
| fdcf9c5327 | |||
| 45c714cbb5 | |||
| 7352a309a0 | |||
| b297fe6f59 | |||
| e575212c49 | |||
| c52dc10c9e | |||
| d35c913249 | |||
| 9bac59b952 | |||
| 5016253922 | |||
| 03893071fc | |||
| d3dc94c04b | |||
| af0feabb6a | |||
| 81ab0a414f | |||
| ecd6ca0172 | |||
| db7ee192f7 | |||
| 2ec0b601fa | |||
| 79feb6d5d2 | |||
| 8013b760e3 | |||
| a29b8e5b36 | |||
| 9ef487a7a5 | |||
| 563fa46ba4 | |||
| 7865c06863 | |||
| 3d53b9244d | |||
| f2afa4dd50 | |||
| 893ecec55e | |||
| 401584dbd8 | |||
| b234b0bded | |||
| b9b2c6a013 | |||
| 1d2efa0d25 | |||
| 93ec092eaf | |||
| 29ae492983 | |||
| b9f6a59a20 | |||
| d74551216f | |||
| d4302ae51b | |||
| 9d5fb0b201 | |||
| e0a5fe4002 | |||
| f9d9a0a4bd | |||
| 78f0c7b119 | |||
| c6d8343de2 | |||
| 0ccd11e587 | |||
| b486711d68 | |||
| 2eb4c5e960 | |||
| 85aa740c98 | |||
| 6415848383 | |||
| beb9460538 | |||
| c030770be7 | |||
| 0180342dff | |||
| b97748d3dc | |||
| 9d4977db00 | |||
| f095284faa | |||
| 401c2f42f9 | |||
| eb0348d47c | |||
| 1f46240ba9 | |||
| 14870726e0 | |||
| c7d6a2eecb | |||
| ce61eb2174 | |||
| f3df21ef0a | |||
| 5eb554e008 | |||
| e5e7c3fad3 | |||
| 2a8b9ab75e | |||
| c8f0ffb42f | |||
| b3e68b96cf | |||
| ae7a550a09 | |||
| e069bbb800 | |||
| 17ff6be6a9 | |||
| d42489c67a | |||
| 3ea72e5d21 | |||
| 762854ad7a | |||
| 10465066ee | |||
| 0cf9f51816 | |||
| 3d5e2340ca | |||
| e2047afa42 | |||
| 231b39d2dc | |||
| dddce30368 | |||
| e0e4ba2bd7 | |||
| e0eadb6b76 | |||
| 483e5dfbea | |||
| 8aa9d8213d | |||
| a74f71c935 | |||
| 87b81e53f0 | |||
| a2816e31c3 | |||
| f78af9f27b | |||
| 98138a0a60 | |||
| e639b6303e | |||
| 99fb3ebe00 | |||
| 5829840409 | |||
| 4699ab5500 | |||
| 69fc7f39b7 | |||
| 510a962a52 | |||
| 570fc3cfb2 | |||
| 5d211f2fa6 | |||
| dcb127c14d | |||
| 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 | |||
| d9e7984279 | |||
| e5b9900d3b | |||
| fc3f1431b2 | |||
| c8bf2f4cb1 | |||
| d16555ec4b | |||
| 3c9415b1c2 | |||
| 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 | |||
| 03aaab6f8b | |||
| c8af154205 | |||
| 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 |
@@ -2,19 +2,31 @@
|
|||||||
default.properties
|
default.properties
|
||||||
gen
|
gen
|
||||||
assets/www/cordova.js
|
assets/www/cordova.js
|
||||||
|
framework/assets/www/.tmp*
|
||||||
local.properties
|
local.properties
|
||||||
framework/proguard.cfg
|
framework/lib
|
||||||
framework/cordova.jar
|
proguard.cfg
|
||||||
framework/cordova-*.jar
|
proguard.cfg
|
||||||
framework/phonegap-*.jar
|
proguard-project.txt
|
||||||
framework/bin
|
framework/bin
|
||||||
framework/test/org/apache/cordova/*.class
|
framework/test/org/apache/cordova/*.class
|
||||||
framework/assets/www/.DS_Store
|
framework/assets/www/.DS_Store
|
||||||
framework/assets/www/cordova-*.js
|
framework/assets/www/cordova-*.js
|
||||||
framework/assets/www/phonegap-*.js
|
framework/assets/www/phonegap-*.js
|
||||||
|
framework/libs
|
||||||
|
test/libs
|
||||||
example
|
example
|
||||||
./test
|
./test
|
||||||
tmp
|
test/bin
|
||||||
*.tmp
|
test/assets/www/.tmp*
|
||||||
test/libs/*.jar
|
tmp/**
|
||||||
bin/node_modules
|
bin/node_modules
|
||||||
|
.metadata
|
||||||
|
tmp/**/*
|
||||||
|
Thumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
|
*.swp
|
||||||
|
*.class
|
||||||
|
*.jar
|
||||||
|
|||||||
@@ -15,21 +15,25 @@ indicate that the project has yet to be fully endorsed by the ASF.
|
|||||||
Requires
|
Requires
|
||||||
---
|
---
|
||||||
|
|
||||||
- Java JDK 1.5
|
- Java JDK 1.5 or greater
|
||||||
- Apache ANT
|
- Apache ANT 1.8.0 or greater
|
||||||
- Android SDK [http://developer.android.com](http://developer.android.com)
|
- Android SDK [http://developer.android.com](http://developer.android.com)
|
||||||
- Apache Commons Codec [http://commons.apache.org/codec/](http://commons.apache.org/codec/)
|
- 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
|
Building
|
||||||
---
|
---
|
||||||
|
|
||||||
To create your cordova.jar, copy the commons codec:
|
To create your cordova.jar, copy the commons codec:
|
||||||
|
|
||||||
mv commons-codec-1.6.jar framework/libs
|
mv commons-codec-1.7.jar framework/libs
|
||||||
|
|
||||||
then run in the framework directory:
|
then run in the framework directory:
|
||||||
|
|
||||||
android update project -p . -t android-15
|
android update project -p . -t android-17
|
||||||
ant jar
|
ant jar
|
||||||
|
|
||||||
|
|
||||||
@@ -57,7 +61,7 @@ Project Commands
|
|||||||
|
|
||||||
These commands live in a generated Cordova Android project.
|
These commands live in a generated Cordova Android project.
|
||||||
|
|
||||||
./cordovap/debug [path] ..................... install to first device
|
./cordova/debug [path] ..................... install to first device
|
||||||
./cordova/emulate .......................... start avd (emulator) named default
|
./cordova/emulate .......................... start avd (emulator) named default
|
||||||
./cordova/log .............................. starts logcat
|
./cordova/log .............................. starts logcat
|
||||||
|
|
||||||
@@ -78,15 +82,10 @@ Start adb logcat (console.log calls output here):
|
|||||||
|
|
||||||
./cordova/log
|
./cordova/log
|
||||||
|
|
||||||
Running the [callback/callback-test](http://github.com/callback/callback-test) tests:
|
|
||||||
---
|
|
||||||
|
|
||||||
./bin/test
|
|
||||||
|
|
||||||
Creating a new Cordova Android Project
|
Creating a new Cordova Android Project
|
||||||
---
|
---
|
||||||
|
|
||||||
./bin/create ~/Desktop/myapp com.phonegap.special MyApp
|
./bin/create ~/Desktop/myapp com.myapp.special MyApp
|
||||||
|
|
||||||
Importing a Cordova Android Project into Eclipse
|
Importing a Cordova Android Project into Eclipse
|
||||||
----
|
----
|
||||||
@@ -98,10 +97,13 @@ Importing a Cordova Android Project into Eclipse
|
|||||||
5. Right click on the project root: Run as > Run Configurations
|
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)
|
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
|
Further Reading
|
||||||
---
|
---
|
||||||
|
|
||||||
- [http://developer.android.com](http://developer.android.com)
|
- [http://developer.android.com](http://developer.android.com)
|
||||||
- [http://docs.phonegap.com](http://docs.phonegap.com)
|
- [http://incubator.apache.org/cordova/](http://incubator.apache.org/cordova/)
|
||||||
- [http://wiki.phonegap.com](http://wiki.phonegap.com)
|
- [http://wiki.apache.org/cordova/](http://wiki.apache.org/cordova/)
|
||||||
|
|||||||
@@ -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.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
./bin/create
|
|
||||||
cd ./example && ./cordova/debug && ./cordova/log
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
#! /usr/bin/env node
|
|
||||||
require('nodeunit').reporters.default.run(['bin/tests'])
|
|
||||||
@@ -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
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#! /bin/sh
|
#! /bin/bash
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
# or more contributor license agreements. See the NOTICE file
|
# or more contributor license agreements. See the NOTICE file
|
||||||
# distributed with this work for additional information
|
# distributed with this work for additional information
|
||||||
@@ -23,52 +23,137 @@
|
|||||||
#
|
#
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
PROJECT_PATH=${1:-"./example"}
|
if [ -z "$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"}
|
PACKAGE=${2:-"org.apache.cordova.example"}
|
||||||
ACTIVITY=${3:-"cordovaExample"}
|
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
|
# clobber any existing example
|
||||||
if [ $# -eq 0 ]
|
if [ -d "$PROJECT_PATH" ]
|
||||||
then
|
then
|
||||||
rm -rf $PROJECT_PATH
|
echo "Project already exists! Delete and recreate"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# cleanup after exit and/or on error
|
||||||
|
function on_exit {
|
||||||
|
# [ -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
|
||||||
|
if [ -f "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js ]
|
||||||
|
then
|
||||||
|
rm "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js
|
||||||
|
fi
|
||||||
|
if [ -f "$BUILD_PATH"/framework/cordova-$VERSION.jar ]
|
||||||
|
then
|
||||||
|
rm "$BUILD_PATH"/framework/cordova-$VERSION.jar
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAppInfoJar {
|
||||||
|
(cd "$BUILD_PATH"/bin/templates/cordova/ApplicationInfo &&
|
||||||
|
javac ApplicationInfo.java &&
|
||||||
|
jar -cfe ../appinfo.jar ApplicationInfo ApplicationInfo.class
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function on_error {
|
||||||
|
echo "An unexpected error occurred: $previous_command exited with $?"
|
||||||
|
echo "Deleting project..."
|
||||||
|
[ -d "$PROJECT_PATH" ] && rm -rf "$PROJECT_PATH"
|
||||||
|
exit "$?"
|
||||||
|
}
|
||||||
|
|
||||||
|
function replace {
|
||||||
|
local pattern=$1
|
||||||
|
local filename=$2
|
||||||
|
# Mac OS X requires -i argument
|
||||||
|
if [[ "$OSTYPE" =~ "darwin" ]]
|
||||||
|
then
|
||||||
|
/usr/bin/sed -i '' -e $pattern "$filename"
|
||||||
|
elif [[ "$OSTYPE" =~ "linux" ]]
|
||||||
|
then
|
||||||
|
/bin/sed -i -e $pattern "$filename"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# we do not want the script to silently fail
|
||||||
|
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
|
||||||
|
trap on_error ERR
|
||||||
|
trap on_exit EXIT
|
||||||
|
|
||||||
|
ANDROID_BIN="${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 ' ' )
|
||||||
|
API_LEVEL=$("$ANDROID_BIN" list target | grep "API level:" | tail -n 1 | cut -f 2 -d ':' | tr -d ' ')
|
||||||
|
|
||||||
|
# if this a distribution release no need to build a jar
|
||||||
|
if [ ! -e "$BUILD_PATH"/cordova-$VERSION.jar ] && [ -d "$BUILD_PATH"/framework ]
|
||||||
|
then
|
||||||
# update the cordova-android framework for the desired target
|
# update the cordova-android framework for the desired target
|
||||||
android update project --target $TARGET --path ./framework
|
"$ANDROID_BIN" update project --target $TARGET --path "$BUILD_PATH"/framework &> /dev/null
|
||||||
|
|
||||||
if [ ! -e ./framework/libs/commons-codec-1.6.jar ]; then
|
if [ ! -e "$BUILD_PATH"/framework/libs/commons-codec-1.7.jar ]; then
|
||||||
# Use curl to get the jar (TODO: Support Apache Mirrors)
|
# 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
|
curl -OL http://archive.apache.org/dist/commons/codec/binaries/commons-codec-1.7-bin.zip &> /dev/null
|
||||||
unzip commons-codec-1.6-bin.zip
|
unzip commons-codec-1.7-bin.zip &> /dev/null
|
||||||
mkdir -p ./framework/libs
|
mkdir -p "$BUILD_PATH"/framework/libs
|
||||||
cp commons-codec-1.6/commons-codec-1.6.jar ./framework/libs/
|
cp commons-codec-1.7/commons-codec-1.7.jar "$BUILD_PATH"/framework/libs
|
||||||
fi
|
# cleanup yo
|
||||||
|
rm commons-codec-1.7-bin.zip && rm -rf commons-codec-1.7
|
||||||
|
fi
|
||||||
|
|
||||||
# compile cordova.js and cordova.jar
|
# compile cordova.js and cordova.jar
|
||||||
cd ./framework && ant jar && cd ../
|
(cd "$BUILD_PATH"/framework && ant jar &> /dev/null )
|
||||||
|
fi
|
||||||
|
|
||||||
# copy all the bin scripts etc in there
|
# create new android project
|
||||||
cp -R ./bin/templates/project/ $PROJECT_PATH
|
"$ANDROID_BIN" create project --target $TARGET --path "$PROJECT_PATH" --package $PACKAGE --activity $ACTIVITY &> /dev/null
|
||||||
|
|
||||||
# copy in cordova.js
|
# copy project template
|
||||||
cp ./framework/assets/www/cordova-$VERSION.js $PROJECT_PATH/.cordova/android/cordova-$VERSION.js
|
cp -r "$BUILD_PATH"/bin/templates/project/assets "$PROJECT_PATH"
|
||||||
|
cp -r "$BUILD_PATH"/bin/templates/project/res "$PROJECT_PATH"
|
||||||
|
|
||||||
# copy in cordova.jar
|
# copy cordova.js, cordova.jar and res/xml
|
||||||
cp ./framework/cordova-$VERSION.jar $PROJECT_PATH/.cordova/android/cordova-$VERSION.jar
|
if [ -d "$BUILD_PATH"/framework ]
|
||||||
|
then
|
||||||
|
cp -r "$BUILD_PATH"/framework/res/xml "$PROJECT_PATH"/res
|
||||||
|
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
|
||||||
|
else
|
||||||
|
cp -r "$BUILD_PATH"/xml "$PROJECT_PATH"/res/xml
|
||||||
|
cp "$BUILD_PATH"/cordova-$VERSION.js "$PROJECT_PATH"/assets/www/cordova-$VERSION.js
|
||||||
|
cp "$BUILD_PATH"/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
|
||||||
|
fi
|
||||||
|
|
||||||
# copy in res/xml
|
# interpolate the activity name and package
|
||||||
cp ./framework/res/xml/cordova.xml $PROJECT_PATH/.cordova/android/cordova.xml
|
cp "$BUILD_PATH"/bin/templates/project/Activity.java "$ACTIVITY_PATH"
|
||||||
cp ./framework/res/xml/plugins.xml $PROJECT_PATH/.cordova/android/plugins.xml
|
replace "s/__ACTIVITY__/${ACTIVITY}/g" "$ACTIVITY_PATH"
|
||||||
|
replace "s/__ID__/${PACKAGE}/g" "$ACTIVITY_PATH"
|
||||||
|
|
||||||
# app properties
|
cp "$BUILD_PATH"/bin/templates/project/AndroidManifest.xml "$MANIFEST_PATH"
|
||||||
cat > $PROJECT_PATH/.cordova/config <<eom
|
replace "s/__ACTIVITY__/${ACTIVITY}/g" "$MANIFEST_PATH"
|
||||||
VERSION=$VERSION
|
replace "s/__PACKAGE__/${PACKAGE}/g" "$MANIFEST_PATH"
|
||||||
PROJECT_PATH=$PROJECT_PATH
|
replace "s/__APILEVEL__/${API_LEVEL}/g" "$MANIFEST_PATH"
|
||||||
PACKAGE=$PACKAGE
|
|
||||||
ACTIVITY=$ACTIVITY
|
|
||||||
TARGET=$TARGET
|
|
||||||
eom
|
|
||||||
|
|
||||||
(cd $PROJECT_PATH && ./cordova/create)
|
# creating cordova folder and copying run/build/log/launch scripts
|
||||||
|
mkdir "$PROJECT_PATH"/cordova
|
||||||
|
createAppInfoJar
|
||||||
|
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/build "$PROJECT_PATH"/cordova/build
|
||||||
|
cp "$BUILD_PATH"/bin/templates/cordova/release "$PROJECT_PATH"/cordova/release
|
||||||
|
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/run "$PROJECT_PATH"/cordova/run
|
||||||
|
|||||||
@@ -1 +1,32 @@
|
|||||||
cscript bin\create.js %*
|
:: 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.
|
||||||
|
|
||||||
|
@ECHO OFF
|
||||||
|
IF NOT DEFINED JAVA_HOME GOTO MISSING
|
||||||
|
FOR %%X in (java.exe javac.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
|
||||||
|
|||||||
@@ -24,14 +24,23 @@
|
|||||||
* ./create [path package activity]
|
* ./create [path package activity]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var fso = WScript.CreateObject('Scripting.FileSystemObject');
|
||||||
|
|
||||||
function read(filename) {
|
function read(filename) {
|
||||||
WScript.Echo('Reading in ' + filename);
|
|
||||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||||
var f=fso.OpenTextFile(filename, 1);
|
var f=fso.OpenTextFile(filename, 1);
|
||||||
var s=f.ReadAll();
|
var s=f.ReadAll();
|
||||||
f.Close();
|
f.Close();
|
||||||
return s;
|
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 setApiLevel() {
|
||||||
|
var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/API level:\s\d+/g);
|
||||||
|
return targets[targets.length - 1].replace(/API level: /, "");
|
||||||
|
}
|
||||||
function write(filename, contents) {
|
function write(filename, contents) {
|
||||||
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
var fso=WScript.CreateObject("Scripting.FileSystemObject");
|
||||||
var f=fso.OpenTextFile(filename, 2, true);
|
var f=fso.OpenTextFile(filename, 2, true);
|
||||||
@@ -41,24 +50,81 @@ function write(filename, contents) {
|
|||||||
function replaceInFile(filename, regexp, replacement) {
|
function replaceInFile(filename, regexp, replacement) {
|
||||||
write(filename, read(filename).replace(regexp, replacement));
|
write(filename, read(filename).replace(regexp, replacement));
|
||||||
}
|
}
|
||||||
function exec(s, output) {
|
function exec(command) {
|
||||||
WScript.Echo('Executing ' + s);
|
var oShell=shell.Exec(command);
|
||||||
var o=shell.Exec(s);
|
while (oShell.Status == 0) {
|
||||||
while (o.Status == 0) {
|
if(!oShell.StdOut.AtEndOfStream) {
|
||||||
WScript.Sleep(100);
|
var line = oShell.StdOut.ReadLine();
|
||||||
|
// XXX: Change to verbose mode
|
||||||
|
// WScript.StdOut.WriteLine(line);
|
||||||
|
}
|
||||||
|
WScript.sleep(100);
|
||||||
}
|
}
|
||||||
WScript.Echo("Command exited with code " + o.Status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function fork(s) {
|
function createAppInfoJar() {
|
||||||
WScript.Echo('Executing ' + s);
|
if(!fso.FileExists(ROOT+"\\bin\\templates\\cordova\\appinfo.jar")) {
|
||||||
var o=shell.Exec(s);
|
WScript.Echo("Creating appinfo.jar...");
|
||||||
while (o.Status != 1) {
|
var cur = shell.CurrentDirectory;
|
||||||
WScript.Sleep(100);
|
shell.CurrentDirectory = ROOT+"\\bin\\templates\\cordova\\ApplicationInfo";
|
||||||
|
exec("javac ApplicationInfo.java");
|
||||||
|
exec("jar -cfe ..\\appinfo.jar ApplicationInfo ApplicationInfo.class");
|
||||||
|
shell.CurrentDirectory = cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.7.jar')) {
|
||||||
|
// We need the .jar
|
||||||
|
var url = 'http://archive.apache.org/dist/commons/codec/binaries/commons-codec-1.7-bin.zip';
|
||||||
|
var libsPath = ROOT + '\\framework\\libs';
|
||||||
|
var savePath = libsPath + '\\commons-codec-1.7-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.7\\commons-codec-1.7.jar', ROOT + '\\framework\\libs\\commons-codec-1.7.jar');
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
fso.DeleteFile(ROOT + '\\framework\\libs\\commons-codec-1.7-bin.zip');
|
||||||
|
fso.DeleteFolder(ROOT + '\\framework\\libs\\commons-codec-1.7', 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",
|
var args = WScript.Arguments, PROJECT_PATH="example",
|
||||||
@@ -69,106 +135,80 @@ var args = WScript.Arguments, PROJECT_PATH="example",
|
|||||||
var ROOT = WScript.ScriptFullName.split('\\bin\\create.js').join('');
|
var ROOT = WScript.ScriptFullName.split('\\bin\\create.js').join('');
|
||||||
|
|
||||||
if (args.Count() == 3) {
|
if (args.Count() == 3) {
|
||||||
WScript.Echo('Found expected arguments');
|
|
||||||
PROJECT_PATH=args(0);
|
PROJECT_PATH=args(0);
|
||||||
PACKAGE=args(1);
|
PACKAGE=args(1);
|
||||||
ACTIVITY=args(2);
|
ACTIVITY=args(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(fso.FolderExists(PROJECT_PATH)) {
|
||||||
|
WScript.Echo("Project already exists!");
|
||||||
|
WScript.Quit(1);
|
||||||
|
}
|
||||||
|
|
||||||
var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
|
var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
|
||||||
var ACTIVITY_PATH=PROJECT_PATH+'\\src\\'+PACKAGE_AS_PATH+'\\'+ACTIVITY+'.java';
|
var ACTIVITY_PATH=PROJECT_PATH+'\\src\\'+PACKAGE_AS_PATH+'\\'+ACTIVITY+'.java';
|
||||||
var MANIFEST_PATH=PROJECT_PATH+'\\AndroidManifest.xml';
|
var MANIFEST_PATH=PROJECT_PATH+'\\AndroidManifest.xml';
|
||||||
var TARGET=shell.Exec('android.bat list targets').StdOut.ReadAll().match(/id:\s([0-9]).*/)[1];
|
var TARGET=setTarget();
|
||||||
var VERSION=read('VERSION').replace(/\r\n/,'').replace(/\n/,'');
|
var API_LEVEL=setApiLevel();
|
||||||
|
var VERSION=read(ROOT+'\\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
|
|
||||||
*/
|
|
||||||
|
|
||||||
// create the project
|
// create the project
|
||||||
|
WScript.Echo("Creating new android project...");
|
||||||
exec('android.bat create project --target '+TARGET+' --path '+PROJECT_PATH+' --package '+PACKAGE+' --activity '+ACTIVITY);
|
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
|
// build from source. distro should have these files
|
||||||
exec('android.bat update project --target '+TARGET+' --path framework');
|
if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
|
||||||
|
!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.js')) {
|
||||||
// pull down commons codec if necessary
|
WScript.Echo("Building jar and js files...");
|
||||||
var fso = WScript.CreateObject('Scripting.FileSystemObject');
|
// update the cordova framework project to a target that exists on this machine
|
||||||
if (!fso.FileExists(ROOT + '\\framework\\libs\\commons-codec-1.6.jar')) {
|
exec('android.bat update project --target '+TARGET+' --path '+ROOT+'\\framework');
|
||||||
// We need the .jar
|
// pull down commons codec if necessary
|
||||||
var url = 'http://mirror.symnds.com/software/Apache//commons/codec/binaries/commons-codec-1.6-bin.zip';
|
downloadCommonsCodec();
|
||||||
var savePath = ROOT + '\\framework\\libs\\commons-codec-1.6-bin.zip';
|
exec('ant.bat -f \"'+ ROOT +'\\framework\\build.xml\" jar');
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 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');
|
|
||||||
|
|
||||||
// copy in the project template
|
// copy in the project template
|
||||||
exec('cmd /c xcopy bin\\templates\\project\\* '+PROJECT_PATH+' /S /Y');
|
WScript.Echo("Copying template files...");
|
||||||
|
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 example www assets
|
// check if we have the source or the distro files
|
||||||
exec('cmd /c xcopy ' + PROJECT_PATH + '\\cordova\\assets ' + PROJECT_PATH + ' /S /Y');
|
WScript.Echo("Copying js, jar & config.xml files...");
|
||||||
|
if(fso.FolderExists(ROOT + '\\framework')) {
|
||||||
|
exec('%comspec% /c copy "'+ROOT+'"\\framework\\assets\\www\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
|
||||||
|
exec('%comspec% /c copy "'+ROOT+'"\\framework\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
|
||||||
|
fso.CreateFolder(PROJECT_PATH + '\\res\\xml');
|
||||||
|
exec('%comspec% /c copy "'+ROOT+'"\\framework\\res\\xml\\config.xml ' + PROJECT_PATH + '\\res\\xml\\config.xml /Y');
|
||||||
|
} else {
|
||||||
|
// copy in cordova.js
|
||||||
|
exec('%comspec% /c copy "'+ROOT+'"\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
|
||||||
|
// copy in cordova.jar
|
||||||
|
exec('%comspec% /c copy "'+ROOT+'"\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
|
||||||
|
// copy in xml
|
||||||
|
fso.CreateFolder(PROJECT_PATH + '\\res\\xml');
|
||||||
|
exec('%comspec% /c copy "'+ROOT+'"\\xml\\config.xml ' + PROJECT_PATH + '\\res\\xml\\config.xml /Y');
|
||||||
|
}
|
||||||
|
|
||||||
// copy in cordova.js
|
// copy cordova scripts
|
||||||
exec('cmd /c copy framework\\assets\\js\\cordova.android.js '+PROJECT_PATH+'\\.cordova\\android\\cordova-'+VERSION+'.js /Y');
|
fso.CreateFolder(PROJECT_PATH + '\\cordova');
|
||||||
|
createAppInfoJar();
|
||||||
|
WScript.Echo("Copying cordova command tools...");
|
||||||
|
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\\build.bat ' + PROJECT_PATH + '\\cordova\\build.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\\run.bat ' + PROJECT_PATH + '\\cordova\\run.bat /Y');
|
||||||
|
|
||||||
// copy in cordova.jar
|
// interpolate the activity name and package
|
||||||
exec('cmd /c copy framework\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\.cordova\\android\\cordova-'+VERSION+'.jar /Y');
|
WScript.Echo("Updating AndroidManifest.xml and Main Activity...");
|
||||||
|
replaceInFile(ACTIVITY_PATH, /__ACTIVITY__/, ACTIVITY);
|
||||||
|
replaceInFile(ACTIVITY_PATH, /__ID__/, PACKAGE);
|
||||||
|
|
||||||
// copy in xml
|
replaceInFile(MANIFEST_PATH, /__ACTIVITY__/, ACTIVITY);
|
||||||
exec('cmd /c copy framework\\res\\xml\\cordova.xml ' + PROJECT_PATH + '\\.cordova\\android\\cordova.xml /Y');
|
replaceInFile(MANIFEST_PATH, /__PACKAGE__/, PACKAGE);
|
||||||
exec('cmd /c copy framework\\res\\xml\\plugins.xml ' + PROJECT_PATH + '\\.cordova\\android\\plugins.xml /Y');
|
replaceInFile(MANIFEST_PATH, /__APILEVEL__/, API_LEVEL);
|
||||||
|
|
||||||
// write out config file
|
cleanup();
|
||||||
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);
|
|
||||||
|
|
||||||
// run project-specific create process
|
|
||||||
fork('cscript.exe ' + PROJECT_PATH + '\\cordova\\create.js');
|
|
||||||
|
|||||||
@@ -18,9 +18,5 @@
|
|||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "http://git-wip-us.apache.org/repos/asf/incubator-cordova-android.git"
|
"url": "http://git-wip-us.apache.org/repos/asf/incubator-cordova-android.git"
|
||||||
},
|
|
||||||
"dependencies":{
|
|
||||||
"coffee-script":"1.1.2",
|
|
||||||
"nodeunit":"0.5.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
|
||||||
|
|
||||||
|
bash "$CORDOVA_PATH"/cordova build
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
:: 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.
|
||||||
|
|
||||||
|
%~dp0\cordova.bat build
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
|
||||||
|
|
||||||
|
bash "$CORDOVA_PATH"/cordova clean
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
:: 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.
|
||||||
|
|
||||||
|
%~dp0\cordova.bat clean
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
PROJECT_PATH=$( cd "$( dirname "$0" )/.." && pwd )
|
||||||
|
|
||||||
|
function check_devices {
|
||||||
|
# FIXME
|
||||||
|
local devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep device`
|
||||||
|
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
|
||||||
|
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
|
||||||
|
read -t 5 -p "> " avd_id
|
||||||
|
# default value if input timeout
|
||||||
|
if [ $avd_id -eq 1000 ] ; then avd_id=0 ; fi
|
||||||
|
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 conjunction with other commands
|
||||||
|
function log {
|
||||||
|
adb logcat
|
||||||
|
}
|
||||||
|
|
||||||
|
function run {
|
||||||
|
clean && emulate && wait_for_device && install && launch
|
||||||
|
}
|
||||||
|
|
||||||
|
function install {
|
||||||
|
|
||||||
|
declare -a devices=($(adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep device | cut -f 1))
|
||||||
|
local device_id="1000" #FIXME: hopefully user does not have 1000 AVDs
|
||||||
|
|
||||||
|
if [ ${#devices[@]} == 0 ]
|
||||||
|
then
|
||||||
|
# should not reach here. Emulator should launch or device should be attached
|
||||||
|
echo "Emulator not running or device not attached. Could not install debug package"
|
||||||
|
exit 70
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${#devices[@]} == 1 ]
|
||||||
|
then
|
||||||
|
export ANDROID_SERIAL=${devices[0]}
|
||||||
|
# User has more than 1 AVD
|
||||||
|
elif [ ${#devices[@]} -gt 1 ]
|
||||||
|
then
|
||||||
|
while [ -z ${devices[$device_id]} ]
|
||||||
|
do
|
||||||
|
echo "Choose from one of the following devices/emulators [0 to $((${#devices[@]}-1))]:"
|
||||||
|
for(( i = 0 ; i < ${#devices[@]} ; i++ ))
|
||||||
|
do
|
||||||
|
echo "$i) ${devices[$i]}"
|
||||||
|
done
|
||||||
|
read -t 5 -p "> " device_id
|
||||||
|
# default value if input timeout
|
||||||
|
if [ $device_id -eq 1000 ] ; then device_id=0 ; fi
|
||||||
|
done
|
||||||
|
export ANDROID_SERIAL=${devices[$device_id]}
|
||||||
|
fi
|
||||||
|
|
||||||
|
ant debug install
|
||||||
|
}
|
||||||
|
|
||||||
|
function build {
|
||||||
|
ant debug
|
||||||
|
}
|
||||||
|
|
||||||
|
function release {
|
||||||
|
ant release
|
||||||
|
}
|
||||||
|
|
||||||
|
function wait_for_device {
|
||||||
|
local i="0"
|
||||||
|
echo -n "Waiting for device..."
|
||||||
|
|
||||||
|
while [ $i -lt 300 ]
|
||||||
|
do
|
||||||
|
if [ $(check_devices) -eq 0 ]
|
||||||
|
then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
sleep 1
|
||||||
|
i=$[i+1]
|
||||||
|
echo -n "."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# Device timeout: emulator has not started in time or device not attached
|
||||||
|
if [ $i -eq 300 ]
|
||||||
|
then
|
||||||
|
echo "device timeout!"
|
||||||
|
exit 69
|
||||||
|
else
|
||||||
|
echo "connected!"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function launch {
|
||||||
|
local launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml)
|
||||||
|
adb shell am start -n $launch_str
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO parse arguments
|
||||||
|
(cd "$PROJECT_PATH" && $1)
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
:: 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.
|
||||||
|
|
||||||
|
@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
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
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 device_running() {
|
||||||
|
var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
|
||||||
|
if(local_devices.match(/\w+\tdevice/)) {
|
||||||
|
WScript.Echo("Yes");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
WScript.Echo("No");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function emulate() {
|
||||||
|
// don't run emulator if a device is plugged in or if emulator is already running
|
||||||
|
if(device_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() {
|
||||||
|
WScript.Echo("Cleaning project...");
|
||||||
|
exec("%comspec% /c ant.bat clean -f "+ROOT+"\\build.xml 2>&1");
|
||||||
|
}
|
||||||
|
|
||||||
|
function build() {
|
||||||
|
WScript.Echo("Building project...");
|
||||||
|
exec("%comspec% /c ant.bat debug -f "+ROOT+"\\build.xml 2>&1");
|
||||||
|
}
|
||||||
|
|
||||||
|
function install() {
|
||||||
|
WScript.Echo("Building/Installing project...");
|
||||||
|
exec("%comspec% /c ant.bat debug install -f "+ROOT+"\\build.xml 2>&1");
|
||||||
|
}
|
||||||
|
|
||||||
|
function log() {
|
||||||
|
shell.Run("%comspec% /c adb logcat");
|
||||||
|
}
|
||||||
|
|
||||||
|
function launch() {
|
||||||
|
WScript.Echo("Launching app...");
|
||||||
|
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 run() {
|
||||||
|
var i=0;
|
||||||
|
clean();
|
||||||
|
emulate();
|
||||||
|
WScript.Stdout.Write('Waiting for device...');
|
||||||
|
while(!device_running() && i < 300) {
|
||||||
|
WScript.Stdout.Write('.');
|
||||||
|
WScript.sleep(1000);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
if(i == 300) {
|
||||||
|
WScript.Stderr.WriteLine("device/emulator timeout!");
|
||||||
|
} else {
|
||||||
|
WScript.Stdout.WriteLine("connected!");
|
||||||
|
}
|
||||||
|
install();
|
||||||
|
launch();
|
||||||
|
}
|
||||||
|
var args = WScript.Arguments;
|
||||||
|
if(args.count() != 1) {
|
||||||
|
WScript.StdErr.Write("An error has occured!\n");
|
||||||
|
WScript.Quit(1);
|
||||||
|
}
|
||||||
|
eval(args(0)+"()");
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CORDOVA_PATH=$( cd "$( dirname "$0" )/.." && pwd )
|
||||||
|
|
||||||
|
bash "$CORDOVA_PATH"/cordova/cordova log
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
:: 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.
|
||||||
|
|
||||||
|
%~dp0\cordova.bat log
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
|
||||||
|
|
||||||
|
bash "$CORDOVA_PATH"/cordova release
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
|
||||||
|
|
||||||
|
bash "$CORDOVA_PATH"/cordova run
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
%~dp0\cordova.bat run
|
||||||
@@ -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!
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
under the License.
|
under the License.
|
||||||
-->
|
-->
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:windowSoftInputMode="adjustPan"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:windowSoftInputMode="adjustPan"
|
||||||
package="__PACKAGE__" android:versionName="1.1" android:versionCode="5">
|
package="__PACKAGE__" android:versionName="1.1" android:versionCode="5" android:hardwareAccelerated="true">
|
||||||
<supports-screens
|
<supports-screens
|
||||||
android:largeScreens="true"
|
android:largeScreens="true"
|
||||||
android:normalScreens="true"
|
android:normalScreens="true"
|
||||||
@@ -47,9 +47,11 @@
|
|||||||
|
|
||||||
|
|
||||||
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
||||||
|
android:hardwareAccelerated="true"
|
||||||
android:debuggable="true">
|
android:debuggable="true">
|
||||||
<activity android:name="__ACTIVITY__" android:label="@string/app_name"
|
<activity android:name="__ACTIVITY__" android:label="@string/app_name"
|
||||||
android:configChanges="orientation|keyboardHidden">
|
android:theme="@android:style/Theme.Black.NoTitleBar"
|
||||||
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
@@ -57,5 +59,5 @@
|
|||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="5" />
|
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="__APILEVEL__"/>
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
* {
|
||||||
|
-webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
-webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
|
||||||
|
-webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
|
||||||
|
-webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
|
||||||
|
background-color:#E4E4E4;
|
||||||
|
background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
|
||||||
|
background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
|
||||||
|
background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
|
||||||
|
background-image:-webkit-gradient(
|
||||||
|
linear,
|
||||||
|
left top,
|
||||||
|
left bottom,
|
||||||
|
color-stop(0, #A7A7A7),
|
||||||
|
color-stop(0.51, #E4E4E4)
|
||||||
|
);
|
||||||
|
background-attachment:fixed;
|
||||||
|
font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
|
||||||
|
font-size:12px;
|
||||||
|
height:100%;
|
||||||
|
margin:0px;
|
||||||
|
padding:0px;
|
||||||
|
text-transform:uppercase;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Portrait layout (default) */
|
||||||
|
.app {
|
||||||
|
background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
|
||||||
|
position:absolute; /* position in the center of the screen */
|
||||||
|
left:50%;
|
||||||
|
top:50%;
|
||||||
|
height:50px; /* text area height */
|
||||||
|
width:225px; /* text area width */
|
||||||
|
text-align:center;
|
||||||
|
padding:180px 0px 0px 0px; /* image height is 200px (bottom 20px are overlapped with text) */
|
||||||
|
margin:-115px 0px 0px -112px; /* offset vertical: half of image height and text area height */
|
||||||
|
/* offset horizontal: half of text area width */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Landscape layout (with min-width) */
|
||||||
|
@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
|
||||||
|
.app {
|
||||||
|
background-position:left center;
|
||||||
|
padding:75px 0px 75px 170px; /* padding-top + padding-bottom + text area = image height */
|
||||||
|
margin:-90px 0px 0px -198px; /* offset vertical: half of image height */
|
||||||
|
/* offset horizontal: half of image width and text area width */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size:24px;
|
||||||
|
font-weight:normal;
|
||||||
|
margin:0px;
|
||||||
|
overflow:visible;
|
||||||
|
padding:0px;
|
||||||
|
text-align:center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event {
|
||||||
|
border-radius:4px;
|
||||||
|
-webkit-border-radius:4px;
|
||||||
|
color:#FFFFFF;
|
||||||
|
font-size:12px;
|
||||||
|
margin:0px 30px;
|
||||||
|
padding:2px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event.listening {
|
||||||
|
background-color:#333333;
|
||||||
|
display:block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event.received {
|
||||||
|
background-color:#4B946A;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade {
|
||||||
|
from { opacity: 1.0; }
|
||||||
|
50% { opacity: 0.4; }
|
||||||
|
to { opacity: 1.0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes fade {
|
||||||
|
from { opacity: 1.0; }
|
||||||
|
50% { opacity: 0.4; }
|
||||||
|
to { opacity: 1.0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.blink {
|
||||||
|
animation:fade 3000ms infinite;
|
||||||
|
-webkit-animation:fade 3000ms infinite;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta name="format-detection" content="telephone=no" />
|
||||||
|
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/index.css" />
|
||||||
|
<title>Hello World</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="app">
|
||||||
|
<h1>Apache Cordova</h1>
|
||||||
|
<div id="deviceready" class="blink">
|
||||||
|
<p class="event listening">Connecting to Device</p>
|
||||||
|
<p class="event received">Device is Ready</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="cordova-2.3.0rc2.js"></script>
|
||||||
|
<script type="text/javascript" src="js/index.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
app.initialize();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
var app = {
|
||||||
|
// Application Constructor
|
||||||
|
initialize: function() {
|
||||||
|
this.bindEvents();
|
||||||
|
},
|
||||||
|
// Bind Event Listeners
|
||||||
|
//
|
||||||
|
// Bind any events that are required on startup. Common events are:
|
||||||
|
// 'load', 'deviceready', 'offline', and 'online'.
|
||||||
|
bindEvents: function() {
|
||||||
|
document.addEventListener('deviceready', this.onDeviceReady, false);
|
||||||
|
},
|
||||||
|
// deviceready Event Handler
|
||||||
|
//
|
||||||
|
// The scope of 'this' is the event. In order to call the 'receivedEvent'
|
||||||
|
// function, we must explicity call 'app.receivedEvent(...);'
|
||||||
|
onDeviceReady: function() {
|
||||||
|
app.receivedEvent('deviceready');
|
||||||
|
},
|
||||||
|
// Update DOM on a Received Event
|
||||||
|
receivedEvent: function(id) {
|
||||||
|
var parentElement = document.getElementById(id);
|
||||||
|
var listeningElement = parentElement.querySelector('.listening');
|
||||||
|
var receivedElement = parentElement.querySelector('.received');
|
||||||
|
|
||||||
|
listeningElement.setAttribute('style', 'display:none;');
|
||||||
|
receivedElement.setAttribute('style', 'display:block;');
|
||||||
|
|
||||||
|
console.log('Received Event: ' + id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 213 KiB |
|
After Width: | Height: | Size: 217 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 478 KiB |
|
After Width: | Height: | Size: 493 KiB |
@@ -0,0 +1,68 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Jasmine Spec Runner</title>
|
||||||
|
|
||||||
|
<!-- jasmine source -->
|
||||||
|
<link rel="shortcut icon" type="image/png" href="spec/lib/jasmine-1.2.0/jasmine_favicon.png">
|
||||||
|
<link rel="stylesheet" type="text/css" href="spec/lib/jasmine-1.2.0/jasmine.css">
|
||||||
|
<script type="text/javascript" src="spec/lib/jasmine-1.2.0/jasmine.js"></script>
|
||||||
|
<script type="text/javascript" src="spec/lib/jasmine-1.2.0/jasmine-html.js"></script>
|
||||||
|
|
||||||
|
<!-- include source files here... -->
|
||||||
|
<script type="text/javascript" src="js/index.js"></script>
|
||||||
|
|
||||||
|
<!-- include spec files here... -->
|
||||||
|
<script type="text/javascript" src="spec/helper.js"></script>
|
||||||
|
<script type="text/javascript" src="spec/index.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
(function() {
|
||||||
|
var jasmineEnv = jasmine.getEnv();
|
||||||
|
jasmineEnv.updateInterval = 1000;
|
||||||
|
|
||||||
|
var htmlReporter = new jasmine.HtmlReporter();
|
||||||
|
|
||||||
|
jasmineEnv.addReporter(htmlReporter);
|
||||||
|
|
||||||
|
jasmineEnv.specFilter = function(spec) {
|
||||||
|
return htmlReporter.specFilter(spec);
|
||||||
|
};
|
||||||
|
|
||||||
|
var currentWindowOnload = window.onload;
|
||||||
|
|
||||||
|
window.onload = function() {
|
||||||
|
if (currentWindowOnload) {
|
||||||
|
currentWindowOnload();
|
||||||
|
}
|
||||||
|
execJasmine();
|
||||||
|
};
|
||||||
|
|
||||||
|
function execJasmine() {
|
||||||
|
jasmineEnv.execute();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="stage" style="display:none;"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
afterEach(function() {
|
||||||
|
document.getElementById('stage').innerHTML = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
var helper = {
|
||||||
|
trigger: function(obj, name) {
|
||||||
|
var e = document.createEvent('Event');
|
||||||
|
e.initEvent(name, true, true);
|
||||||
|
obj.dispatchEvent(e);
|
||||||
|
},
|
||||||
|
getComputedStyle: function(querySelector, property) {
|
||||||
|
var element = document.querySelector(querySelector);
|
||||||
|
return window.getComputedStyle(element).getPropertyValue(property);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
describe('app', function() {
|
||||||
|
describe('initialize', function() {
|
||||||
|
it('should bind deviceready', function() {
|
||||||
|
runs(function() {
|
||||||
|
spyOn(app, 'onDeviceReady');
|
||||||
|
app.initialize();
|
||||||
|
helper.trigger(window.document, 'deviceready');
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return (app.onDeviceReady.calls.length > 0);
|
||||||
|
}, 'onDeviceReady should be called once', 500);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(app.onDeviceReady).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onDeviceReady', function() {
|
||||||
|
it('should report that it fired', function() {
|
||||||
|
spyOn(app, 'receivedEvent');
|
||||||
|
app.onDeviceReady();
|
||||||
|
expect(app.receivedEvent).toHaveBeenCalledWith('deviceready');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('receivedEvent', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
var el = document.getElementById('stage');
|
||||||
|
el.innerHTML = ['<div id="deviceready">',
|
||||||
|
' <p class="event listening">Listening</p>',
|
||||||
|
' <p class="event received">Received</p>',
|
||||||
|
'</div>'].join('\n');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide the listening element', function() {
|
||||||
|
app.receivedEvent('deviceready');
|
||||||
|
var displayStyle = helper.getComputedStyle('#deviceready .listening', 'display');
|
||||||
|
expect(displayStyle).toEqual('none');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the received element', function() {
|
||||||
|
app.receivedEvent('deviceready');
|
||||||
|
var displayStyle = helper.getComputedStyle('#deviceready .received', 'display');
|
||||||
|
expect(displayStyle).toEqual('block');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
Copyright (c) 2008-2011 Pivotal Labs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@@ -0,0 +1,616 @@
|
|||||||
|
jasmine.HtmlReporterHelpers = {};
|
||||||
|
|
||||||
|
jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
|
||||||
|
var el = document.createElement(type);
|
||||||
|
|
||||||
|
for (var i = 2; i < arguments.length; i++) {
|
||||||
|
var child = arguments[i];
|
||||||
|
|
||||||
|
if (typeof child === 'string') {
|
||||||
|
el.appendChild(document.createTextNode(child));
|
||||||
|
} else {
|
||||||
|
if (child) {
|
||||||
|
el.appendChild(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var attr in attrs) {
|
||||||
|
if (attr == "className") {
|
||||||
|
el[attr] = attrs[attr];
|
||||||
|
} else {
|
||||||
|
el.setAttribute(attr, attrs[attr]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return el;
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
|
||||||
|
var results = child.results();
|
||||||
|
var status = results.passed() ? 'passed' : 'failed';
|
||||||
|
if (results.skipped) {
|
||||||
|
status = 'skipped';
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
|
||||||
|
var parentDiv = this.dom.summary;
|
||||||
|
var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
|
||||||
|
var parent = child[parentSuite];
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
if (typeof this.views.suites[parent.id] == 'undefined') {
|
||||||
|
this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
|
||||||
|
}
|
||||||
|
parentDiv = this.views.suites[parent.id].element;
|
||||||
|
}
|
||||||
|
|
||||||
|
parentDiv.appendChild(childElement);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
|
||||||
|
for(var fn in jasmine.HtmlReporterHelpers) {
|
||||||
|
ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.HtmlReporter = function(_doc) {
|
||||||
|
var self = this;
|
||||||
|
var doc = _doc || window.document;
|
||||||
|
|
||||||
|
var reporterView;
|
||||||
|
|
||||||
|
var dom = {};
|
||||||
|
|
||||||
|
// Jasmine Reporter Public Interface
|
||||||
|
self.logRunningSpecs = false;
|
||||||
|
|
||||||
|
self.reportRunnerStarting = function(runner) {
|
||||||
|
var specs = runner.specs() || [];
|
||||||
|
|
||||||
|
if (specs.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
createReporterDom(runner.env.versionString());
|
||||||
|
doc.body.appendChild(dom.reporter);
|
||||||
|
|
||||||
|
reporterView = new jasmine.HtmlReporter.ReporterView(dom);
|
||||||
|
reporterView.addSpecs(specs, self.specFilter);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.reportRunnerResults = function(runner) {
|
||||||
|
reporterView && reporterView.complete();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.reportSuiteResults = function(suite) {
|
||||||
|
reporterView.suiteComplete(suite);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.reportSpecStarting = function(spec) {
|
||||||
|
if (self.logRunningSpecs) {
|
||||||
|
self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.reportSpecResults = function(spec) {
|
||||||
|
reporterView.specComplete(spec);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.log = function() {
|
||||||
|
var console = jasmine.getGlobal().console;
|
||||||
|
if (console && console.log) {
|
||||||
|
if (console.log.apply) {
|
||||||
|
console.log.apply(console, arguments);
|
||||||
|
} else {
|
||||||
|
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.specFilter = function(spec) {
|
||||||
|
if (!focusedSpecName()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return spec.getFullName().indexOf(focusedSpecName()) === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
return self;
|
||||||
|
|
||||||
|
function focusedSpecName() {
|
||||||
|
var specName;
|
||||||
|
|
||||||
|
(function memoizeFocusedSpec() {
|
||||||
|
if (specName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var paramMap = [];
|
||||||
|
var params = doc.location.search.substring(1).split('&');
|
||||||
|
|
||||||
|
for (var i = 0; i < params.length; i++) {
|
||||||
|
var p = params[i].split('=');
|
||||||
|
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
specName = paramMap.spec;
|
||||||
|
})();
|
||||||
|
|
||||||
|
return specName;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createReporterDom(version) {
|
||||||
|
dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
|
||||||
|
dom.banner = self.createDom('div', { className: 'banner' },
|
||||||
|
self.createDom('span', { className: 'title' }, "Jasmine "),
|
||||||
|
self.createDom('span', { className: 'version' }, version)),
|
||||||
|
|
||||||
|
dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
|
||||||
|
dom.alert = self.createDom('div', {className: 'alert'}),
|
||||||
|
dom.results = self.createDom('div', {className: 'results'},
|
||||||
|
dom.summary = self.createDom('div', { className: 'summary' }),
|
||||||
|
dom.details = self.createDom('div', { id: 'details' }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) {
|
||||||
|
this.startedAt = new Date();
|
||||||
|
this.runningSpecCount = 0;
|
||||||
|
this.completeSpecCount = 0;
|
||||||
|
this.passedCount = 0;
|
||||||
|
this.failedCount = 0;
|
||||||
|
this.skippedCount = 0;
|
||||||
|
|
||||||
|
this.createResultsMenu = function() {
|
||||||
|
this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
|
||||||
|
this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
|
||||||
|
' | ',
|
||||||
|
this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
|
||||||
|
|
||||||
|
this.summaryMenuItem.onclick = function() {
|
||||||
|
dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.detailsMenuItem.onclick = function() {
|
||||||
|
showDetails();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.addSpecs = function(specs, specFilter) {
|
||||||
|
this.totalSpecCount = specs.length;
|
||||||
|
|
||||||
|
this.views = {
|
||||||
|
specs: {},
|
||||||
|
suites: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var i = 0; i < specs.length; i++) {
|
||||||
|
var spec = specs[i];
|
||||||
|
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
|
||||||
|
if (specFilter(spec)) {
|
||||||
|
this.runningSpecCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.specComplete = function(spec) {
|
||||||
|
this.completeSpecCount++;
|
||||||
|
|
||||||
|
if (isUndefined(this.views.specs[spec.id])) {
|
||||||
|
this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
|
||||||
|
}
|
||||||
|
|
||||||
|
var specView = this.views.specs[spec.id];
|
||||||
|
|
||||||
|
switch (specView.status()) {
|
||||||
|
case 'passed':
|
||||||
|
this.passedCount++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'failed':
|
||||||
|
this.failedCount++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'skipped':
|
||||||
|
this.skippedCount++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
specView.refresh();
|
||||||
|
this.refresh();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.suiteComplete = function(suite) {
|
||||||
|
var suiteView = this.views.suites[suite.id];
|
||||||
|
if (isUndefined(suiteView)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
suiteView.refresh();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.refresh = function() {
|
||||||
|
|
||||||
|
if (isUndefined(this.resultsMenu)) {
|
||||||
|
this.createResultsMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// currently running UI
|
||||||
|
if (isUndefined(this.runningAlert)) {
|
||||||
|
this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
|
||||||
|
dom.alert.appendChild(this.runningAlert);
|
||||||
|
}
|
||||||
|
this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
|
||||||
|
|
||||||
|
// skipped specs UI
|
||||||
|
if (isUndefined(this.skippedAlert)) {
|
||||||
|
this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
|
||||||
|
|
||||||
|
if (this.skippedCount === 1 && isDefined(dom.alert)) {
|
||||||
|
dom.alert.appendChild(this.skippedAlert);
|
||||||
|
}
|
||||||
|
|
||||||
|
// passing specs UI
|
||||||
|
if (isUndefined(this.passedAlert)) {
|
||||||
|
this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
|
||||||
|
}
|
||||||
|
this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
|
||||||
|
|
||||||
|
// failing specs UI
|
||||||
|
if (isUndefined(this.failedAlert)) {
|
||||||
|
this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
|
||||||
|
}
|
||||||
|
this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
|
||||||
|
|
||||||
|
if (this.failedCount === 1 && isDefined(dom.alert)) {
|
||||||
|
dom.alert.appendChild(this.failedAlert);
|
||||||
|
dom.alert.appendChild(this.resultsMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
// summary info
|
||||||
|
this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
|
||||||
|
this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
|
||||||
|
};
|
||||||
|
|
||||||
|
this.complete = function() {
|
||||||
|
dom.alert.removeChild(this.runningAlert);
|
||||||
|
|
||||||
|
this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
|
||||||
|
|
||||||
|
if (this.failedCount === 0) {
|
||||||
|
dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
|
||||||
|
} else {
|
||||||
|
showDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
|
||||||
|
};
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
function showDetails() {
|
||||||
|
if (dom.reporter.className.search(/showDetails/) === -1) {
|
||||||
|
dom.reporter.className += " showDetails";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isUndefined(obj) {
|
||||||
|
return typeof obj === 'undefined';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDefined(obj) {
|
||||||
|
return !isUndefined(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
function specPluralizedFor(count) {
|
||||||
|
var str = count + " spec";
|
||||||
|
if (count > 1) {
|
||||||
|
str += "s"
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
|
||||||
|
|
||||||
|
|
||||||
|
jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
|
||||||
|
this.spec = spec;
|
||||||
|
this.dom = dom;
|
||||||
|
this.views = views;
|
||||||
|
|
||||||
|
this.symbol = this.createDom('li', { className: 'pending' });
|
||||||
|
this.dom.symbolSummary.appendChild(this.symbol);
|
||||||
|
|
||||||
|
this.summary = this.createDom('div', { className: 'specSummary' },
|
||||||
|
this.createDom('a', {
|
||||||
|
className: 'description',
|
||||||
|
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
|
||||||
|
title: this.spec.getFullName()
|
||||||
|
}, this.spec.description)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.detail = this.createDom('div', { className: 'specDetail' },
|
||||||
|
this.createDom('a', {
|
||||||
|
className: 'description',
|
||||||
|
href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
|
||||||
|
title: this.spec.getFullName()
|
||||||
|
}, this.spec.getFullName())
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.HtmlReporter.SpecView.prototype.status = function() {
|
||||||
|
return this.getSpecStatus(this.spec);
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
|
||||||
|
this.symbol.className = this.status();
|
||||||
|
|
||||||
|
switch (this.status()) {
|
||||||
|
case 'skipped':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'passed':
|
||||||
|
this.appendSummaryToSuiteDiv();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'failed':
|
||||||
|
this.appendSummaryToSuiteDiv();
|
||||||
|
this.appendFailureDetail();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
|
||||||
|
this.summary.className += ' ' + this.status();
|
||||||
|
this.appendToSummary(this.spec, this.summary);
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
|
||||||
|
this.detail.className += ' ' + this.status();
|
||||||
|
|
||||||
|
var resultItems = this.spec.results().getItems();
|
||||||
|
var messagesDiv = this.createDom('div', { className: 'messages' });
|
||||||
|
|
||||||
|
for (var i = 0; i < resultItems.length; i++) {
|
||||||
|
var result = resultItems[i];
|
||||||
|
|
||||||
|
if (result.type == 'log') {
|
||||||
|
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
|
||||||
|
} else if (result.type == 'expect' && result.passed && !result.passed()) {
|
||||||
|
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
|
||||||
|
|
||||||
|
if (result.trace.stack) {
|
||||||
|
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messagesDiv.childNodes.length > 0) {
|
||||||
|
this.detail.appendChild(messagesDiv);
|
||||||
|
this.dom.details.appendChild(this.detail);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
|
||||||
|
this.suite = suite;
|
||||||
|
this.dom = dom;
|
||||||
|
this.views = views;
|
||||||
|
|
||||||
|
this.element = this.createDom('div', { className: 'suite' },
|
||||||
|
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.appendToSummary(this.suite, this.element);
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.HtmlReporter.SuiteView.prototype.status = function() {
|
||||||
|
return this.getSpecStatus(this.suite);
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
|
||||||
|
this.element.className += " " + this.status();
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
|
||||||
|
|
||||||
|
/* @deprecated Use jasmine.HtmlReporter instead
|
||||||
|
*/
|
||||||
|
jasmine.TrivialReporter = function(doc) {
|
||||||
|
this.document = doc || document;
|
||||||
|
this.suiteDivs = {};
|
||||||
|
this.logRunningSpecs = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
|
||||||
|
var el = document.createElement(type);
|
||||||
|
|
||||||
|
for (var i = 2; i < arguments.length; i++) {
|
||||||
|
var child = arguments[i];
|
||||||
|
|
||||||
|
if (typeof child === 'string') {
|
||||||
|
el.appendChild(document.createTextNode(child));
|
||||||
|
} else {
|
||||||
|
if (child) { el.appendChild(child); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var attr in attrs) {
|
||||||
|
if (attr == "className") {
|
||||||
|
el[attr] = attrs[attr];
|
||||||
|
} else {
|
||||||
|
el.setAttribute(attr, attrs[attr]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return el;
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
|
||||||
|
var showPassed, showSkipped;
|
||||||
|
|
||||||
|
this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
|
||||||
|
this.createDom('div', { className: 'banner' },
|
||||||
|
this.createDom('div', { className: 'logo' },
|
||||||
|
this.createDom('span', { className: 'title' }, "Jasmine"),
|
||||||
|
this.createDom('span', { className: 'version' }, runner.env.versionString())),
|
||||||
|
this.createDom('div', { className: 'options' },
|
||||||
|
"Show ",
|
||||||
|
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
|
||||||
|
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
|
||||||
|
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
|
||||||
|
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
this.runnerDiv = this.createDom('div', { className: 'runner running' },
|
||||||
|
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
|
||||||
|
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
|
||||||
|
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
|
||||||
|
);
|
||||||
|
|
||||||
|
this.document.body.appendChild(this.outerDiv);
|
||||||
|
|
||||||
|
var suites = runner.suites();
|
||||||
|
for (var i = 0; i < suites.length; i++) {
|
||||||
|
var suite = suites[i];
|
||||||
|
var suiteDiv = this.createDom('div', { className: 'suite' },
|
||||||
|
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
|
||||||
|
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
|
||||||
|
this.suiteDivs[suite.id] = suiteDiv;
|
||||||
|
var parentDiv = this.outerDiv;
|
||||||
|
if (suite.parentSuite) {
|
||||||
|
parentDiv = this.suiteDivs[suite.parentSuite.id];
|
||||||
|
}
|
||||||
|
parentDiv.appendChild(suiteDiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.startedAt = new Date();
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
showPassed.onclick = function(evt) {
|
||||||
|
if (showPassed.checked) {
|
||||||
|
self.outerDiv.className += ' show-passed';
|
||||||
|
} else {
|
||||||
|
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
showSkipped.onclick = function(evt) {
|
||||||
|
if (showSkipped.checked) {
|
||||||
|
self.outerDiv.className += ' show-skipped';
|
||||||
|
} else {
|
||||||
|
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
|
||||||
|
var results = runner.results();
|
||||||
|
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
|
||||||
|
this.runnerDiv.setAttribute("class", className);
|
||||||
|
//do it twice for IE
|
||||||
|
this.runnerDiv.setAttribute("className", className);
|
||||||
|
var specs = runner.specs();
|
||||||
|
var specCount = 0;
|
||||||
|
for (var i = 0; i < specs.length; i++) {
|
||||||
|
if (this.specFilter(specs[i])) {
|
||||||
|
specCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
|
||||||
|
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
|
||||||
|
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
|
||||||
|
|
||||||
|
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
|
||||||
|
var results = suite.results();
|
||||||
|
var status = results.passed() ? 'passed' : 'failed';
|
||||||
|
if (results.totalCount === 0) { // todo: change this to check results.skipped
|
||||||
|
status = 'skipped';
|
||||||
|
}
|
||||||
|
this.suiteDivs[suite.id].className += " " + status;
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
|
||||||
|
if (this.logRunningSpecs) {
|
||||||
|
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
|
||||||
|
var results = spec.results();
|
||||||
|
var status = results.passed() ? 'passed' : 'failed';
|
||||||
|
if (results.skipped) {
|
||||||
|
status = 'skipped';
|
||||||
|
}
|
||||||
|
var specDiv = this.createDom('div', { className: 'spec ' + status },
|
||||||
|
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
|
||||||
|
this.createDom('a', {
|
||||||
|
className: 'description',
|
||||||
|
href: '?spec=' + encodeURIComponent(spec.getFullName()),
|
||||||
|
title: spec.getFullName()
|
||||||
|
}, spec.description));
|
||||||
|
|
||||||
|
|
||||||
|
var resultItems = results.getItems();
|
||||||
|
var messagesDiv = this.createDom('div', { className: 'messages' });
|
||||||
|
for (var i = 0; i < resultItems.length; i++) {
|
||||||
|
var result = resultItems[i];
|
||||||
|
|
||||||
|
if (result.type == 'log') {
|
||||||
|
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
|
||||||
|
} else if (result.type == 'expect' && result.passed && !result.passed()) {
|
||||||
|
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
|
||||||
|
|
||||||
|
if (result.trace.stack) {
|
||||||
|
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messagesDiv.childNodes.length > 0) {
|
||||||
|
specDiv.appendChild(messagesDiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.suiteDivs[spec.suite.id].appendChild(specDiv);
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.TrivialReporter.prototype.log = function() {
|
||||||
|
var console = jasmine.getGlobal().console;
|
||||||
|
if (console && console.log) {
|
||||||
|
if (console.log.apply) {
|
||||||
|
console.log.apply(console, arguments);
|
||||||
|
} else {
|
||||||
|
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.TrivialReporter.prototype.getLocation = function() {
|
||||||
|
return this.document.location;
|
||||||
|
};
|
||||||
|
|
||||||
|
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
|
||||||
|
var paramMap = {};
|
||||||
|
var params = this.getLocation().search.substring(1).split('&');
|
||||||
|
for (var i = 0; i < params.length; i++) {
|
||||||
|
var p = params[i].split('=');
|
||||||
|
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!paramMap.spec) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return spec.getFullName().indexOf(paramMap.spec) === 0;
|
||||||
|
};
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
|
||||||
|
|
||||||
|
#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
|
||||||
|
#HTMLReporter a { text-decoration: none; }
|
||||||
|
#HTMLReporter a:hover { text-decoration: underline; }
|
||||||
|
#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
|
||||||
|
#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
|
||||||
|
#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
|
||||||
|
#HTMLReporter .version { color: #aaaaaa; }
|
||||||
|
#HTMLReporter .banner { margin-top: 14px; }
|
||||||
|
#HTMLReporter .duration { color: #aaaaaa; float: right; }
|
||||||
|
#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
|
||||||
|
#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
|
||||||
|
#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
|
||||||
|
#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
|
||||||
|
#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
|
||||||
|
#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
|
||||||
|
#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
|
||||||
|
#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
|
||||||
|
#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
|
||||||
|
#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
|
||||||
|
#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
|
||||||
|
#HTMLReporter .runningAlert { background-color: #666666; }
|
||||||
|
#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
|
||||||
|
#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
|
||||||
|
#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
|
||||||
|
#HTMLReporter .passingAlert { background-color: #a6b779; }
|
||||||
|
#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
|
||||||
|
#HTMLReporter .failingAlert { background-color: #cf867e; }
|
||||||
|
#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
|
||||||
|
#HTMLReporter .results { margin-top: 14px; }
|
||||||
|
#HTMLReporter #details { display: none; }
|
||||||
|
#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
|
||||||
|
#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
|
||||||
|
#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
|
||||||
|
#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
|
||||||
|
#HTMLReporter.showDetails .summary { display: none; }
|
||||||
|
#HTMLReporter.showDetails #details { display: block; }
|
||||||
|
#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
|
||||||
|
#HTMLReporter .summary { margin-top: 14px; }
|
||||||
|
#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
|
||||||
|
#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
|
||||||
|
#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
|
||||||
|
#HTMLReporter .description + .suite { margin-top: 0; }
|
||||||
|
#HTMLReporter .suite { margin-top: 14px; }
|
||||||
|
#HTMLReporter .suite a { color: #333333; }
|
||||||
|
#HTMLReporter #details .specDetail { margin-bottom: 28px; }
|
||||||
|
#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
|
||||||
|
#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
|
||||||
|
#HTMLReporter .resultMessage span.result { display: block; }
|
||||||
|
#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
|
||||||
|
|
||||||
|
#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
|
||||||
|
#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
|
||||||
|
#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
|
||||||
|
#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
|
||||||
|
#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
|
||||||
|
#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
|
||||||
|
#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
|
||||||
|
#TrivialReporter .runner.running { background-color: yellow; }
|
||||||
|
#TrivialReporter .options { text-align: right; font-size: .8em; }
|
||||||
|
#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
|
||||||
|
#TrivialReporter .suite .suite { margin: 5px; }
|
||||||
|
#TrivialReporter .suite.passed { background-color: #dfd; }
|
||||||
|
#TrivialReporter .suite.failed { background-color: #fdd; }
|
||||||
|
#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
|
||||||
|
#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
|
||||||
|
#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
|
||||||
|
#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
|
||||||
|
#TrivialReporter .spec.skipped { background-color: #bbb; }
|
||||||
|
#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
|
||||||
|
#TrivialReporter .passed { background-color: #cfc; display: none; }
|
||||||
|
#TrivialReporter .failed { background-color: #fbb; }
|
||||||
|
#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
|
||||||
|
#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
|
||||||
|
#TrivialReporter .resultMessage .mismatch { color: black; }
|
||||||
|
#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
|
||||||
|
#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
|
||||||
|
#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
|
||||||
|
#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
|
||||||
|
#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
<!DOCTYPE HTML>
|
|
||||||
<!--
|
|
||||||
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.
|
|
||||||
-->
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=320; user-scalable=no" />
|
|
||||||
<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.1.js"></script>
|
|
||||||
<script type="text/javascript" charset="utf-8" src="main.js"></script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body onload="init();" id="stage" class="theme">
|
|
||||||
<h1>Welcome to Cordova!</h1>
|
|
||||||
<h2>this file is located at assets/www/index.html</h2>
|
|
||||||
<div id="info">
|
|
||||||
<h4>Platform: <span id="platform"> </span>, Version: <span id="version"> </span></h4>
|
|
||||||
<h4>UUID: <span id="uuid"> </span>, Name: <span id="name"> </span></h4>
|
|
||||||
<h4>Width: <span id="width"> </span>, Height: <span id="height">
|
|
||||||
</span>, Color Depth: <span id="colorDepth"></span></h4>
|
|
||||||
</div>
|
|
||||||
<dl id="accel-data">
|
|
||||||
<dt>X:</dt><dd id="x"> </dd>
|
|
||||||
<dt>Y:</dt><dd id="y"> </dd>
|
|
||||||
<dt>Z:</dt><dd id="z"> </dd>
|
|
||||||
</dl>
|
|
||||||
<a href="#" class="btn large" onclick="toggleAccel();">Toggle Accelerometer</a>
|
|
||||||
<a href="#" class="btn large" onclick="getLocation();">Get Location</a>
|
|
||||||
<a href="tel:411" class="btn large">Call 411</a>
|
|
||||||
<a href="#" class="btn large" onclick="beep();">Beep</a>
|
|
||||||
<a href="#" class="btn large" onclick="vibrate();">Vibrate</a>
|
|
||||||
<a href="#" class="btn large" onclick="show_pic();">Get a Picture</a>
|
|
||||||
<a href="#" class="btn large" onclick="get_contacts();return false;">Get Phone's Contacts</a>
|
|
||||||
<a href="#" class="btn large" onclick="check_network();return false;">Check Network</a>
|
|
||||||
<dl>
|
|
||||||
<dt>Compass Heading:</dt><dd id="h">Off</dd>
|
|
||||||
</dl>
|
|
||||||
<a href="#" class="btn large" onclick="toggleCompass();return false;">Toggle Compass</a>
|
|
||||||
<div id="viewport" class="viewport" style="display: none;">
|
|
||||||
<img style="width:60px;height:60px" id="test_img" src="" />
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
@@ -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
|
|
||||||
@@ -1,24 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
exports['you are sane'] = (test) ->
|
|
||||||
test.expect 1
|
|
||||||
test.ok true, "this assertion should always pass"
|
|
||||||
test.done()
|
|
||||||
@@ -1,18 +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.
|
|
||||||
*/
|
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
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 substituted 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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
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 substituted properly
|
||||||
|
});
|
||||||
|
|
||||||
|
// make sure config.xml was added
|
||||||
|
path.exists(util.format('%s/res/xml/config.xml', project_path), function(exists) {
|
||||||
|
assert(exists, 'config.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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
<classpathentry kind="src" path="gen"/>
|
<classpathentry kind="src" path="gen"/>
|
||||||
<classpathentry kind="lib" path="libs/commons-codec-1.6.jar"/>
|
<classpathentry kind="lib" path="libs/commons-codec-1.7.jar"/>
|
||||||
|
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||||
<classpathentry kind="output" path="bin/classes"/>
|
<classpathentry kind="output" path="bin/classes"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
||||||
android:debuggable="true">
|
android:debuggable="true">
|
||||||
<activity android:name=".StandAlone" android:windowSoftInputMode="adjustPan"
|
<activity android:name=".StandAlone" android:windowSoftInputMode="adjustPan"
|
||||||
android:label="@string/app_name" android:configChanges="orientation|keyboardHidden">
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
@@ -64,5 +64,5 @@
|
|||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="2" />
|
<uses-sdk android:minSdkVersion="7" />
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title></title>
|
<title></title>
|
||||||
<script src="cordova-1.8.1.js"></script>
|
<script src="cordova-2.3.0rc2.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,37 @@
|
|||||||
</filterchain>
|
</filterchain>
|
||||||
</loadfile>
|
</loadfile>
|
||||||
|
|
||||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
<!-- check that the version of ant is at least 1.8.0, as is needed
|
||||||
It contains the path to the SDK. It should *NOT* be checked into
|
for the dblQuote property -->
|
||||||
Version Control Systems. -->
|
<antversion property="thisantversion" atleast="1.8.0" />
|
||||||
|
<fail message="The required minimum version of ant is 1.8.0, you have ${ant.version}"
|
||||||
|
unless="thisantversion" />
|
||||||
|
|
||||||
|
<!-- check that commons codec is available. You should copy the codec jar to
|
||||||
|
framework/libs, as it is not included in the Cordova distribution.
|
||||||
|
The name of the jar file in framework/libs does not matter. -->
|
||||||
|
<available classname="org.apache.commons.codec.binary.Base64"
|
||||||
|
property="exists.base64"
|
||||||
|
ignoresystemclasses="true">
|
||||||
|
<classpath>
|
||||||
|
<pathelement path="${classpath}" />
|
||||||
|
<fileset dir="libs">
|
||||||
|
<include name="*.jar" />
|
||||||
|
</fileset>
|
||||||
|
</classpath>
|
||||||
|
</available>
|
||||||
|
<fail message="You need to put a copy of Apache Commons Codec jar in the framework/libs directory"
|
||||||
|
unless="exists.base64" />
|
||||||
|
|
||||||
|
<!-- The local.properties file is created and updated by the 'android'
|
||||||
|
tool. (For example "sdkdir/tools/android update project -p ." inside
|
||||||
|
of this directory where the AndroidManifest.xml file exists. This
|
||||||
|
properties file that gets built contains the path to the SDK. It
|
||||||
|
should *NOT* be checked into Version Control Systems since it holds
|
||||||
|
data about the local machine. -->
|
||||||
|
<available file="local.properties" property="exists.local.properties" />
|
||||||
|
<fail message="You need to create the file 'local.properties' by running 'android update project -p .' here."
|
||||||
|
unless="exists.local.properties" />
|
||||||
<loadproperties srcFile="local.properties" />
|
<loadproperties srcFile="local.properties" />
|
||||||
|
|
||||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||||
@@ -66,13 +94,13 @@
|
|||||||
application and should be checked into Version Control Systems. -->
|
application and should be checked into Version Control Systems. -->
|
||||||
<loadproperties srcFile="project.properties" />
|
<loadproperties srcFile="project.properties" />
|
||||||
|
|
||||||
<!-- quick check on sdk.dir -->
|
<!-- quick check on sdk.dir -->
|
||||||
<fail
|
<fail
|
||||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project'"
|
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project'"
|
||||||
unless="sdk.dir"
|
unless="sdk.dir"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- version-tag: custom -->
|
<!-- version-tag: custom -->
|
||||||
<!-- extension targets. Uncomment the ones where you want to do custom work
|
<!-- extension targets. Uncomment the ones where you want to do custom work
|
||||||
in between standard targets -->
|
in between standard targets -->
|
||||||
<!--
|
<!--
|
||||||
@@ -106,7 +134,7 @@
|
|||||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||||
in order to avoid having your file be overridden by tools such as "android update project"
|
in order to avoid having your file be overridden by tools such as "android update project"
|
||||||
-->
|
-->
|
||||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||||
|
|
||||||
<!-- Combine JavaScript files into one cordova-uncompressed.js file. -->
|
<!-- Combine JavaScript files into one cordova-uncompressed.js file. -->
|
||||||
<target name="build-javascript" depends="clean">
|
<target name="build-javascript" depends="clean">
|
||||||
@@ -122,7 +150,7 @@
|
|||||||
<!-- update project files to reference cordova-x.x.x.min.js -->
|
<!-- update project files to reference cordova-x.x.x.min.js -->
|
||||||
<replaceregexp match="cordova(.*)\.js" replace="cordova-${version}.js" byline="true">
|
<replaceregexp match="cordova(.*)\.js" replace="cordova-${version}.js" byline="true">
|
||||||
<fileset file="assets/www/index.html" />
|
<fileset file="assets/www/index.html" />
|
||||||
<fileset file="../bin/templates/project/cordova/templates/project/assets/www/index.html" />
|
<fileset file="../bin/templates/project/assets/www/index.html" />
|
||||||
</replaceregexp>
|
</replaceregexp>
|
||||||
|
|
||||||
<!-- This is sketchy, but it works, ${dblQuote} does not -->
|
<!-- This is sketchy, but it works, ${dblQuote} does not -->
|
||||||
|
|||||||
@@ -10,5 +10,7 @@
|
|||||||
# Indicates whether an apk should be generated for each density.
|
# Indicates whether an apk should be generated for each density.
|
||||||
split.density=false
|
split.density=false
|
||||||
# Project target.
|
# Project target.
|
||||||
target=Google Inc.:Google APIs:15
|
target=Google Inc.:Google APIs:17
|
||||||
apk-configurations=
|
apk-configurations=
|
||||||
|
renderscript.opt.level=O0
|
||||||
|
android.library=true
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
<?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
|
||||||
|
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>
|
||||||
|
<!--
|
||||||
|
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=".*"/>
|
||||||
|
|
||||||
|
<log level="DEBUG"/>
|
||||||
|
<preference name="useBrowserHistory" value="true" />
|
||||||
|
<preference name="exit-on-suspend" value="false" />
|
||||||
|
<plugins>
|
||||||
|
<plugin name="App" value="org.apache.cordova.App"/>
|
||||||
|
<plugin name="Geolocation" value="org.apache.cordova.GeoBroker"/>
|
||||||
|
<plugin name="Device" value="org.apache.cordova.Device"/>
|
||||||
|
<plugin name="Accelerometer" value="org.apache.cordova.AccelListener"/>
|
||||||
|
<plugin name="Compass" value="org.apache.cordova.CompassListener"/>
|
||||||
|
<plugin name="Media" value="org.apache.cordova.AudioHandler"/>
|
||||||
|
<plugin name="Camera" value="org.apache.cordova.CameraLauncher"/>
|
||||||
|
<plugin name="Contacts" value="org.apache.cordova.ContactManager"/>
|
||||||
|
<plugin name="File" value="org.apache.cordova.FileUtils"/>
|
||||||
|
<plugin name="NetworkStatus" value="org.apache.cordova.NetworkManager"/>
|
||||||
|
<plugin name="Notification" value="org.apache.cordova.Notification"/>
|
||||||
|
<plugin name="Storage" value="org.apache.cordova.Storage"/>
|
||||||
|
<plugin name="FileTransfer" value="org.apache.cordova.FileTransfer"/>
|
||||||
|
<plugin name="Capture" value="org.apache.cordova.Capture"/>
|
||||||
|
<plugin name="Battery" value="org.apache.cordova.BatteryListener"/>
|
||||||
|
<plugin name="SplashScreen" value="org.apache.cordova.SplashScreen"/>
|
||||||
|
<plugin name="Echo" value="org.apache.cordova.Echo" />
|
||||||
|
<plugin name="Globalization" value="org.apache.cordova.Globalization"/>
|
||||||
|
<plugin name="InAppBrowser" value="org.apache.cordova.InAppBrowser"/>
|
||||||
|
</plugins>
|
||||||
|
</cordova>
|
||||||
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?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
|
|
||||||
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>
|
|
||||||
<!--
|
|
||||||
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 -->
|
|
||||||
|
|
||||||
<log level="DEBUG"/>
|
|
||||||
<preference name="classicRender" value="true" />
|
|
||||||
</cordova>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,27 +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 com.phonegap.api;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Plugin interface must be implemented by any plugin classes.
|
|
||||||
*
|
|
||||||
* The execute method is called by the PluginManager.
|
|
||||||
*/
|
|
||||||
public interface IPlugin extends org.apache.cordova.api.IPlugin {
|
|
||||||
}
|
|
||||||
@@ -1,28 +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 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
|
|
||||||
*/
|
|
||||||
public class LOG extends org.apache.cordova.api.LOG {
|
|
||||||
}
|
|
||||||
@@ -1,27 +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 com.phonegap.api;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Plugin interface must be implemented by any plugin classes.
|
|
||||||
*
|
|
||||||
* The execute method is called by the PluginManager.
|
|
||||||
*/
|
|
||||||
public abstract class Plugin extends org.apache.cordova.api.Plugin {
|
|
||||||
}
|
|
||||||
@@ -19,40 +19,44 @@
|
|||||||
package org.apache.cordova;
|
package org.apache.cordova;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.cordova.api.CallbackContext;
|
||||||
import org.apache.cordova.api.CordovaInterface;
|
import org.apache.cordova.api.CordovaInterface;
|
||||||
import org.apache.cordova.api.Plugin;
|
import org.apache.cordova.api.CordovaPlugin;
|
||||||
import org.apache.cordova.api.PluginResult;
|
import org.apache.cordova.api.PluginResult;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.hardware.Sensor;
|
import android.hardware.Sensor;
|
||||||
import android.hardware.SensorEvent;
|
import android.hardware.SensorEvent;
|
||||||
import android.hardware.SensorEventListener;
|
import android.hardware.SensorEventListener;
|
||||||
import android.hardware.SensorManager;
|
import android.hardware.SensorManager;
|
||||||
import android.content.Context;
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
* acceleration values x,y,z.
|
||||||
*/
|
*/
|
||||||
public class AccelListener extends Plugin implements SensorEventListener {
|
public class AccelListener extends CordovaPlugin implements SensorEventListener {
|
||||||
|
|
||||||
public static int STOPPED = 0;
|
public static int STOPPED = 0;
|
||||||
public static int STARTING = 1;
|
public static int STARTING = 1;
|
||||||
public static int RUNNING = 2;
|
public static int RUNNING = 2;
|
||||||
public static int ERROR_FAILED_TO_START = 3;
|
public static int ERROR_FAILED_TO_START = 3;
|
||||||
|
|
||||||
private float x,y,z; // most recent acceleration values
|
private float x,y,z; // most recent acceleration values
|
||||||
private long timestamp; // time of most recent value
|
private long timestamp; // time of most recent value
|
||||||
private int status; // status of listener
|
private int status; // status of listener
|
||||||
private int accuracy = SensorManager.SENSOR_STATUS_UNRELIABLE;
|
private int accuracy = SensorManager.SENSOR_STATUS_UNRELIABLE;
|
||||||
|
|
||||||
private SensorManager sensorManager; // Sensor manager
|
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
|
private CallbackContext callbackContext; // Keeps track of the JS callback context.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an accelerometer listener.
|
* Create an accelerometer listener.
|
||||||
@@ -69,29 +73,26 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
|||||||
* Sets the context of the Command. This can then be used to do things like
|
* Sets the context of the Command. This can then be used to do things like
|
||||||
* get file paths associated with the Activity.
|
* get file paths associated with the Activity.
|
||||||
*
|
*
|
||||||
* @param ctx The context of the main Activity.
|
* @param cordova The context of the main Activity.
|
||||||
|
* @param webView The associated CordovaWebView.
|
||||||
*/
|
*/
|
||||||
public void setContext(CordovaInterface ctx) {
|
@Override
|
||||||
super.setContext(ctx);
|
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
|
||||||
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
|
super.initialize(cordova, webView);
|
||||||
|
this.sensorManager = (SensorManager) cordova.getActivity().getSystemService(Context.SENSOR_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the request and returns PluginResult.
|
* Executes the request.
|
||||||
*
|
*
|
||||||
* @param action The action to execute.
|
* @param action The action to execute.
|
||||||
* @param args JSONArry of arguments for the plugin.
|
* @param args The exec() arguments.
|
||||||
* @param callbackId The callback id used when calling back into JavaScript.
|
* @param callbackId The callback id used when calling back into JavaScript.
|
||||||
* @return A PluginResult object with a status and message.
|
* @return Whether the action was valid.
|
||||||
*/
|
*/
|
||||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
|
||||||
PluginResult.Status status = PluginResult.Status.NO_RESULT;
|
|
||||||
String message = "";
|
|
||||||
PluginResult result = new PluginResult(status, message);
|
|
||||||
result.setKeepCallback(true);
|
|
||||||
|
|
||||||
if (action.equals("start")) {
|
if (action.equals("start")) {
|
||||||
this.callbackId = callbackId;
|
this.callbackContext = callbackContext;
|
||||||
if (this.status != AccelListener.RUNNING) {
|
if (this.status != AccelListener.RUNNING) {
|
||||||
// If not running, then this is an async call, so don't worry about waiting
|
// If not running, then this is an async call, so don't worry about waiting
|
||||||
// We drop the callback onto our stack, call start, and let start and the sensor callback fire off the callback down the road
|
// We drop the callback onto our stack, call start, and let start and the sensor callback fire off the callback down the road
|
||||||
@@ -104,9 +105,13 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Unsupported action
|
// Unsupported action
|
||||||
return new PluginResult(PluginResult.Status.INVALID_ACTION);
|
return false;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT, "");
|
||||||
|
result.setKeepCallback(true);
|
||||||
|
callbackContext.sendPluginResult(result);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,9 +128,9 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
|||||||
//
|
//
|
||||||
/**
|
/**
|
||||||
* Start listening for acceleration sensor.
|
* Start listening for acceleration sensor.
|
||||||
*
|
*
|
||||||
* @return status of listener
|
* @return status of listener
|
||||||
*/
|
*/
|
||||||
private int start() {
|
private int start() {
|
||||||
// If already starting or running, then just return
|
// If already starting or running, then just return
|
||||||
if ((this.status == AccelListener.RUNNING) || (this.status == AccelListener.STARTING)) {
|
if ((this.status == AccelListener.RUNNING) || (this.status == AccelListener.STARTING)) {
|
||||||
@@ -139,29 +144,23 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
|||||||
|
|
||||||
// If found, then register as listener
|
// If found, then register as listener
|
||||||
if ((list != null) && (list.size() > 0)) {
|
if ((list != null) && (list.size() > 0)) {
|
||||||
this.mSensor = list.get(0);
|
this.mSensor = list.get(0);
|
||||||
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_UI);
|
this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_UI);
|
||||||
this.setStatus(AccelListener.STARTING);
|
this.setStatus(AccelListener.STARTING);
|
||||||
} else {
|
} else {
|
||||||
this.setStatus(AccelListener.ERROR_FAILED_TO_START);
|
this.setStatus(AccelListener.ERROR_FAILED_TO_START);
|
||||||
this.fail(AccelListener.ERROR_FAILED_TO_START, "No sensors found to register accelerometer listening to.");
|
this.fail(AccelListener.ERROR_FAILED_TO_START, "No sensors found to register accelerometer listening to.");
|
||||||
return this.status;
|
return this.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until running
|
// Set a timeout callback on the main thread.
|
||||||
long timeout = 2000;
|
Handler handler = new Handler(Looper.getMainLooper());
|
||||||
while ((this.status == STARTING) && (timeout > 0)) {
|
handler.postDelayed(new Runnable() {
|
||||||
timeout = timeout - 100;
|
public void run() {
|
||||||
try {
|
AccelListener.this.timeout();
|
||||||
Thread.sleep(100);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}, 2000);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +175,18 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
|||||||
this.accuracy = SensorManager.SENSOR_STATUS_UNRELIABLE;
|
this.accuracy = SensorManager.SENSOR_STATUS_UNRELIABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an error if the sensor hasn't started.
|
||||||
|
*
|
||||||
|
* Called two seconds after starting the listener.
|
||||||
|
*/
|
||||||
|
private void timeout() {
|
||||||
|
if (this.status == AccelListener.STARTING) {
|
||||||
|
this.setStatus(AccelListener.ERROR_FAILED_TO_START);
|
||||||
|
this.fail(AccelListener.ERROR_FAILED_TO_START, "Accelerometer could not be started.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the accuracy of the sensor has changed.
|
* Called when the accuracy of the sensor has changed.
|
||||||
*
|
*
|
||||||
@@ -210,13 +221,12 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
|||||||
if (this.status == AccelListener.STOPPED) {
|
if (this.status == AccelListener.STOPPED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setStatus(AccelListener.RUNNING);
|
this.setStatus(AccelListener.RUNNING);
|
||||||
|
|
||||||
if (this.accuracy >= SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM) {
|
if (this.accuracy >= SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM) {
|
||||||
|
|
||||||
// Save time that event was received
|
// Save time that event was received
|
||||||
this.timestamp = System.nanoTime();
|
this.timestamp = System.currentTimeMillis();
|
||||||
this.x = event.values[0];
|
this.x = event.values[0];
|
||||||
this.y = event.values[1];
|
this.y = event.values[1];
|
||||||
this.z = event.values[2];
|
this.z = event.values[2];
|
||||||
@@ -225,6 +235,16 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the view navigates.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onReset() {
|
||||||
|
if (this.status == AccelListener.RUNNING) {
|
||||||
|
this.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sends an error back to JS
|
// Sends an error back to JS
|
||||||
private void fail(int code, String message) {
|
private void fail(int code, String message) {
|
||||||
// Error object
|
// Error object
|
||||||
@@ -237,22 +257,19 @@ public class AccelListener extends Plugin implements SensorEventListener {
|
|||||||
}
|
}
|
||||||
PluginResult err = new PluginResult(PluginResult.Status.ERROR, errorObj);
|
PluginResult err = new PluginResult(PluginResult.Status.ERROR, errorObj);
|
||||||
err.setKeepCallback(true);
|
err.setKeepCallback(true);
|
||||||
|
callbackContext.sendPluginResult(err);
|
||||||
this.error(err, this.callbackId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void win() {
|
private void win() {
|
||||||
// Success return object
|
// Success return object
|
||||||
PluginResult result = new PluginResult(PluginResult.Status.OK, this.getAccelerationJSON());
|
PluginResult result = new PluginResult(PluginResult.Status.OK, this.getAccelerationJSON());
|
||||||
result.setKeepCallback(true);
|
result.setKeepCallback(true);
|
||||||
|
callbackContext.sendPluginResult(result);
|
||||||
this.success(result, this.callbackId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setStatus(int status) {
|
private void setStatus(int status) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JSONObject getAccelerationJSON() {
|
private JSONObject getAccelerationJSON() {
|
||||||
JSONObject r = new JSONObject();
|
JSONObject r = new JSONObject();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -19,28 +19,30 @@
|
|||||||
|
|
||||||
package org.apache.cordova;
|
package org.apache.cordova;
|
||||||
|
|
||||||
|
import org.apache.cordova.api.CallbackContext;
|
||||||
|
import org.apache.cordova.api.CordovaPlugin;
|
||||||
import org.apache.cordova.api.LOG;
|
import org.apache.cordova.api.LOG;
|
||||||
import org.apache.cordova.api.Plugin;
|
|
||||||
import org.apache.cordova.api.PluginResult;
|
import org.apache.cordova.api.PluginResult;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class exposes methods in DroidGap that can be called from JavaScript.
|
* This class exposes methods in DroidGap that can be called from JavaScript.
|
||||||
*/
|
*/
|
||||||
public class App extends Plugin {
|
public class App extends CordovaPlugin {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the request and returns PluginResult.
|
* Executes the request and returns PluginResult.
|
||||||
*
|
*
|
||||||
* @param action The action to execute.
|
* @param action The action to execute.
|
||||||
* @param args JSONArry of arguments for the plugin.
|
* @param args JSONArry of arguments for the plugin.
|
||||||
* @param callbackId The callback id used when calling back into JavaScript.
|
* @param callbackContext The callback context from which we were invoked.
|
||||||
* @return A PluginResult object with a status and message.
|
* @return A PluginResult object with a status and message.
|
||||||
*/
|
*/
|
||||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||||
PluginResult.Status status = PluginResult.Status.OK;
|
PluginResult.Status status = PluginResult.Status.OK;
|
||||||
String result = "";
|
String result = "";
|
||||||
|
|
||||||
@@ -48,6 +50,16 @@ public class App extends Plugin {
|
|||||||
if (action.equals("clearCache")) {
|
if (action.equals("clearCache")) {
|
||||||
this.clearCache();
|
this.clearCache();
|
||||||
}
|
}
|
||||||
|
else if (action.equals("show")) {
|
||||||
|
// This gets called from JavaScript onCordovaReady to show the webview.
|
||||||
|
// I recommend we change the name of the Message as spinner/stop is not
|
||||||
|
// indicative of what this actually does (shows the webview).
|
||||||
|
cordova.getActivity().runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
webView.postMessage("spinner", "stop");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
else if (action.equals("loadUrl")) {
|
else if (action.equals("loadUrl")) {
|
||||||
this.loadUrl(args.getString(0), args.optJSONObject(1));
|
this.loadUrl(args.getString(0), args.optJSONObject(1));
|
||||||
}
|
}
|
||||||
@@ -60,19 +72,20 @@ public class App extends Plugin {
|
|||||||
else if (action.equals("backHistory")) {
|
else if (action.equals("backHistory")) {
|
||||||
this.backHistory();
|
this.backHistory();
|
||||||
}
|
}
|
||||||
|
else if (action.equals("overrideButton")) {
|
||||||
|
this.overrideButton(args.getString(0), args.getBoolean(1));
|
||||||
|
}
|
||||||
else if (action.equals("overrideBackbutton")) {
|
else if (action.equals("overrideBackbutton")) {
|
||||||
this.overrideBackbutton(args.getBoolean(0));
|
this.overrideBackbutton(args.getBoolean(0));
|
||||||
}
|
}
|
||||||
else if (action.equals("isBackbuttonOverridden")) {
|
|
||||||
boolean b = this.isBackbuttonOverridden();
|
|
||||||
return new PluginResult(status, b);
|
|
||||||
}
|
|
||||||
else if (action.equals("exitApp")) {
|
else if (action.equals("exitApp")) {
|
||||||
this.exitApp();
|
this.exitApp();
|
||||||
}
|
}
|
||||||
return new PluginResult(status, result);
|
callbackContext.sendPluginResult(new PluginResult(status, result));
|
||||||
|
return true;
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +97,7 @@ public class App extends Plugin {
|
|||||||
* Clear the resource cache.
|
* Clear the resource cache.
|
||||||
*/
|
*/
|
||||||
public void clearCache() {
|
public void clearCache() {
|
||||||
((DroidGap)this.ctx).clearCache();
|
this.webView.clearCache(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,7 +117,7 @@ public class App extends Plugin {
|
|||||||
HashMap<String, Object> params = new HashMap<String, Object>();
|
HashMap<String, Object> params = new HashMap<String, Object>();
|
||||||
if (props != null) {
|
if (props != null) {
|
||||||
JSONArray keys = props.names();
|
JSONArray keys = props.names();
|
||||||
for (int i=0; i<keys.length(); i++) {
|
for (int i = 0; i < keys.length(); i++) {
|
||||||
String key = keys.getString(i);
|
String key = keys.getString(i);
|
||||||
if (key.equals("wait")) {
|
if (key.equals("wait")) {
|
||||||
wait = props.getInt(key);
|
wait = props.getInt(key);
|
||||||
@@ -144,21 +157,22 @@ public class App extends Plugin {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
((DroidGap)this.ctx).showWebPage(url, openExternal, clearHistory, params);
|
this.webView.showWebPage(url, openExternal, clearHistory, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel loadUrl before it has been loaded.
|
* Cancel loadUrl before it has been loaded (Only works on a CordovaInterface class)
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void cancelLoadUrl() {
|
public void cancelLoadUrl() {
|
||||||
((DroidGap)this.ctx).cancelLoadUrl();
|
this.cordova.cancelLoadUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear page history for the app.
|
* Clear page history for the app.
|
||||||
*/
|
*/
|
||||||
public void clearHistory() {
|
public void clearHistory() {
|
||||||
((DroidGap)this.ctx).clearHistory();
|
this.webView.clearHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -166,7 +180,11 @@ public class App extends Plugin {
|
|||||||
* This is the same as pressing the backbutton on Android device.
|
* This is the same as pressing the backbutton on Android device.
|
||||||
*/
|
*/
|
||||||
public void backHistory() {
|
public void backHistory() {
|
||||||
((DroidGap)this.ctx).backHistory();
|
cordova.getActivity().runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
webView.backHistory();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -176,8 +194,20 @@ public class App extends Plugin {
|
|||||||
* @param override T=override, F=cancel override
|
* @param override T=override, F=cancel override
|
||||||
*/
|
*/
|
||||||
public void overrideBackbutton(boolean override) {
|
public void overrideBackbutton(boolean override) {
|
||||||
LOG.i("DroidGap", "WARNING: Back Button Default Behaviour will be overridden. The backbutton event will be fired!");
|
LOG.i("App", "WARNING: Back Button Default Behaviour will be overridden. The backbutton event will be fired!");
|
||||||
((DroidGap)this.ctx).bound = override;
|
webView.bindButton(override);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -186,13 +216,14 @@ public class App extends Plugin {
|
|||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public boolean isBackbuttonOverridden() {
|
public boolean isBackbuttonOverridden() {
|
||||||
return ((DroidGap)this.ctx).bound;
|
return webView.isBackButtonBound();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit the Android application.
|
* Exit the Android application.
|
||||||
*/
|
*/
|
||||||
public void exitApp() {
|
public void exitApp() {
|
||||||
((DroidGap)this.ctx).endActivity();
|
this.webView.postMessage("exit", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,15 +18,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.cordova;
|
package org.apache.cordova;
|
||||||
|
|
||||||
|
import org.apache.cordova.api.CallbackContext;
|
||||||
|
import org.apache.cordova.api.CordovaPlugin;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import org.apache.cordova.api.Plugin;
|
|
||||||
import org.apache.cordova.api.PluginResult;
|
import org.apache.cordova.api.PluginResult;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,89 +42,82 @@ import java.util.HashMap;
|
|||||||
* android_asset: file name must start with /android_asset/sound.mp3
|
* android_asset: file name must start with /android_asset/sound.mp3
|
||||||
* sdcard: file name is just sound.mp3
|
* sdcard: file name is just sound.mp3
|
||||||
*/
|
*/
|
||||||
public class AudioHandler extends Plugin {
|
public class AudioHandler extends CordovaPlugin {
|
||||||
|
|
||||||
public static String TAG = "AudioHandler";
|
public static String TAG = "AudioHandler";
|
||||||
HashMap<String,AudioPlayer> players; // Audio player object
|
HashMap<String, AudioPlayer> players; // Audio player object
|
||||||
ArrayList<AudioPlayer> pausedForPhone; // Audio players that were paused when phone call came in
|
ArrayList<AudioPlayer> pausedForPhone; // Audio players that were paused when phone call came in
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
public AudioHandler() {
|
public AudioHandler() {
|
||||||
this.players = new HashMap<String,AudioPlayer>();
|
this.players = new HashMap<String, AudioPlayer>();
|
||||||
this.pausedForPhone = new ArrayList<AudioPlayer>();
|
this.pausedForPhone = new ArrayList<AudioPlayer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the request and returns PluginResult.
|
* Executes the request and returns PluginResult.
|
||||||
*
|
|
||||||
* @param action The action to execute.
|
* @param action The action to execute.
|
||||||
* @param args JSONArry of arguments for the plugin.
|
* @param args JSONArry of arguments for the plugin.
|
||||||
* @param callbackId The callback id used when calling back into JavaScript.
|
* @param callbackContext The callback context used when calling back into JavaScript.
|
||||||
* @return A PluginResult object with a status and message.
|
* @return A PluginResult object with a status and message.
|
||||||
*/
|
*/
|
||||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||||
PluginResult.Status status = PluginResult.Status.OK;
|
PluginResult.Status status = PluginResult.Status.OK;
|
||||||
String result = "";
|
String result = "";
|
||||||
|
|
||||||
try {
|
if (action.equals("startRecordingAudio")) {
|
||||||
if (action.equals("startRecordingAudio")) {
|
this.startRecordingAudio(args.getString(0), FileUtils.stripFileProtocol(args.getString(1)));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
else if (action.equals("stopRecordingAudio")) {
|
||||||
|
this.stopRecordingAudio(args.getString(0));
|
||||||
/**
|
}
|
||||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
else if (action.equals("startPlayingAudio")) {
|
||||||
*
|
this.startPlayingAudio(args.getString(0), FileUtils.stripFileProtocol(args.getString(1)));
|
||||||
* @param action The action to execute
|
}
|
||||||
* @return T=returns value
|
else if (action.equals("seekToAudio")) {
|
||||||
*/
|
this.seekToAudio(args.getString(0), args.getInt(1));
|
||||||
public boolean isSynch(String action) {
|
}
|
||||||
if (action.equals("getCurrentPositionAudio")) {
|
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));
|
||||||
|
callbackContext.sendPluginResult(new PluginResult(status, f));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (action.equals("getDurationAudio")) {
|
else if (action.equals("getDurationAudio")) {
|
||||||
|
float f = this.getDurationAudio(args.getString(0), args.getString(1));
|
||||||
|
callbackContext.sendPluginResult(new PluginResult(status, f));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
else if (action.equals("create")) {
|
||||||
|
String id = args.getString(0);
|
||||||
|
String src = FileUtils.stripFileProtocol(args.getString(1));
|
||||||
|
AudioPlayer audio = new AudioPlayer(this, id, src);
|
||||||
|
this.players.put(id, audio);
|
||||||
|
}
|
||||||
|
else if (action.equals("release")) {
|
||||||
|
boolean b = this.release(args.getString(0));
|
||||||
|
callbackContext.sendPluginResult(new PluginResult(status, b));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else { // Unrecognized action.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
callbackContext.sendPluginResult(new PluginResult(status, result));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -135,13 +130,22 @@ public class AudioHandler extends Plugin {
|
|||||||
this.players.clear();
|
this.players.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop all audio players and recorders on navigate.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onReset() {
|
||||||
|
onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a message is sent to plugin.
|
* Called when a message is sent to plugin.
|
||||||
*
|
*
|
||||||
* @param id The message id
|
* @param id The message id
|
||||||
* @param data The message data
|
* @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 phone message
|
||||||
if (id.equals("telephone")) {
|
if (id.equals("telephone")) {
|
||||||
@@ -151,7 +155,7 @@ public class AudioHandler extends Plugin {
|
|||||||
|
|
||||||
// Get all audio players and pause them
|
// Get all audio players and pause them
|
||||||
for (AudioPlayer audio : this.players.values()) {
|
for (AudioPlayer audio : this.players.values()) {
|
||||||
if (audio.getState() == AudioPlayer.MEDIA_RUNNING) {
|
if (audio.getState() == AudioPlayer.STATE.MEDIA_RUNNING.ordinal()) {
|
||||||
this.pausedForPhone.add(audio);
|
this.pausedForPhone.add(audio);
|
||||||
audio.pausePlaying();
|
audio.pausePlaying();
|
||||||
}
|
}
|
||||||
@@ -167,6 +171,7 @@ public class AudioHandler extends Plugin {
|
|||||||
this.pausedForPhone.clear();
|
this.pausedForPhone.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
@@ -175,7 +180,6 @@ public class AudioHandler extends Plugin {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Release the audio player instance to save memory.
|
* Release the audio player instance to save memory.
|
||||||
*
|
|
||||||
* @param id The id of the audio player
|
* @param id The id of the audio player
|
||||||
*/
|
*/
|
||||||
private boolean release(String id) {
|
private boolean release(String id) {
|
||||||
@@ -190,43 +194,38 @@ public class AudioHandler extends Plugin {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Start recording and save the specified file.
|
* Start recording and save the specified file.
|
||||||
*
|
|
||||||
* @param id The id of the audio player
|
* @param id The id of the audio player
|
||||||
* @param file The name of the file
|
* @param file The name of the file
|
||||||
*/
|
*/
|
||||||
public void startRecordingAudio(String id, String file) {
|
public void startRecordingAudio(String id, String file) {
|
||||||
// If already recording, then just return;
|
AudioPlayer audio = this.players.get(id);
|
||||||
if (this.players.containsKey(id)) {
|
if ( audio == null) {
|
||||||
return;
|
audio = new AudioPlayer(this, id, file);
|
||||||
|
this.players.put(id, audio);
|
||||||
}
|
}
|
||||||
AudioPlayer audio = new AudioPlayer(this, id);
|
|
||||||
this.players.put(id, audio);
|
|
||||||
audio.startRecording(file);
|
audio.startRecording(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop recording and save to the file specified when recording started.
|
* 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) {
|
public void stopRecordingAudio(String id) {
|
||||||
AudioPlayer audio = this.players.get(id);
|
AudioPlayer audio = this.players.get(id);
|
||||||
if (audio != null) {
|
if (audio != null) {
|
||||||
audio.stopRecording();
|
audio.stopRecording();
|
||||||
this.players.remove(id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start or resume playing audio file.
|
* 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.
|
* @param file The name of the audio file.
|
||||||
*/
|
*/
|
||||||
public void startPlayingAudio(String id, String file) {
|
public void startPlayingAudio(String id, String file) {
|
||||||
AudioPlayer audio = this.players.get(id);
|
AudioPlayer audio = this.players.get(id);
|
||||||
if (audio == null) {
|
if (audio == null) {
|
||||||
audio = new AudioPlayer(this, id);
|
audio = new AudioPlayer(this, id, file);
|
||||||
this.players.put(id, audio);
|
this.players.put(id, audio);
|
||||||
}
|
}
|
||||||
audio.startPlaying(file);
|
audio.startPlaying(file);
|
||||||
@@ -234,10 +233,8 @@ public class AudioHandler extends Plugin {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Seek to a location.
|
* Seek to a location.
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param id The id of the audio player
|
* @param id The id of the audio player
|
||||||
* @param miliseconds int: number of milliseconds to skip 1000 = 1 second
|
* @param milliseconds int: number of milliseconds to skip 1000 = 1 second
|
||||||
*/
|
*/
|
||||||
public void seekToAudio(String id, int milliseconds) {
|
public void seekToAudio(String id, int milliseconds) {
|
||||||
AudioPlayer audio = this.players.get(id);
|
AudioPlayer audio = this.players.get(id);
|
||||||
@@ -248,7 +245,6 @@ public class AudioHandler extends Plugin {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Pause playing.
|
* Pause playing.
|
||||||
*
|
|
||||||
* @param id The id of the audio player
|
* @param id The id of the audio player
|
||||||
*/
|
*/
|
||||||
public void pausePlayingAudio(String id) {
|
public void pausePlayingAudio(String id) {
|
||||||
@@ -260,7 +256,6 @@ public class AudioHandler extends Plugin {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop playing the audio file.
|
* 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) {
|
public void stopPlayingAudio(String id) {
|
||||||
@@ -274,21 +269,19 @@ public class AudioHandler extends Plugin {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current position of playback.
|
* 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
|
* @return position in msec
|
||||||
*/
|
*/
|
||||||
public float getCurrentPositionAudio(String id) {
|
public float getCurrentPositionAudio(String id) {
|
||||||
AudioPlayer audio = this.players.get(id);
|
AudioPlayer audio = this.players.get(id);
|
||||||
if (audio != null) {
|
if (audio != null) {
|
||||||
return(audio.getCurrentPosition()/1000.0f);
|
return (audio.getCurrentPosition() / 1000.0f);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the duration of the audio file.
|
* 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.
|
* @param file The name of the audio file.
|
||||||
* @return The duration in msec.
|
* @return The duration in msec.
|
||||||
@@ -298,14 +291,14 @@ public class AudioHandler extends Plugin {
|
|||||||
// Get audio file
|
// Get audio file
|
||||||
AudioPlayer audio = this.players.get(id);
|
AudioPlayer audio = this.players.get(id);
|
||||||
if (audio != null) {
|
if (audio != null) {
|
||||||
return(audio.getDuration(file));
|
return (audio.getDuration(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not already open, then open the file
|
// If not already open, then open the file
|
||||||
else {
|
else {
|
||||||
audio = new AudioPlayer(this, id);
|
audio = new AudioPlayer(this, id, file);
|
||||||
this.players.put(id, audio);
|
this.players.put(id, audio);
|
||||||
return(audio.getDuration(file));
|
return (audio.getDuration(file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,8 +307,9 @@ public class AudioHandler extends Plugin {
|
|||||||
*
|
*
|
||||||
* @param output 1=earpiece, 2=speaker
|
* @param output 1=earpiece, 2=speaker
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public void setAudioOutputDevice(int output) {
|
public void setAudioOutputDevice(int output) {
|
||||||
AudioManager audiMgr = (AudioManager) this.ctx.getSystemService(Context.AUDIO_SERVICE);
|
AudioManager audiMgr = (AudioManager) this.cordova.getActivity().getSystemService(Context.AUDIO_SERVICE);
|
||||||
if (output == 2) {
|
if (output == 2) {
|
||||||
audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_SPEAKER, AudioManager.ROUTE_ALL);
|
audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_SPEAKER, AudioManager.ROUTE_ALL);
|
||||||
}
|
}
|
||||||
@@ -332,8 +326,9 @@ public class AudioHandler extends Plugin {
|
|||||||
*
|
*
|
||||||
* @return 1=earpiece, 2=speaker
|
* @return 1=earpiece, 2=speaker
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public int getAudioOutputDevice() {
|
public int getAudioOutputDevice() {
|
||||||
AudioManager audiMgr = (AudioManager) this.ctx.getSystemService(Context.AUDIO_SERVICE);
|
AudioManager audiMgr = (AudioManager) this.cordova.getActivity().getSystemService(Context.AUDIO_SERVICE);
|
||||||
if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_EARPIECE) {
|
if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_EARPIECE) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,19 +37,24 @@ import java.io.IOException;
|
|||||||
* Only one file can be played or recorded per class instance.
|
* Only one file can be played or recorded per class instance.
|
||||||
*
|
*
|
||||||
* Local audio files must reside in one of two places:
|
* Local audio files must reside in one of two places:
|
||||||
* android_asset: file name must start with /android_asset/sound.mp3
|
* android_asset: file name must start with /android_asset/sound.mp3
|
||||||
* sdcard: file name is just sound.mp3
|
* sdcard: file name is just sound.mp3
|
||||||
*/
|
*/
|
||||||
public class AudioPlayer implements OnCompletionListener, OnPreparedListener, OnErrorListener {
|
public class AudioPlayer implements OnCompletionListener, OnPreparedListener, OnErrorListener {
|
||||||
|
|
||||||
private static final String LOG_TAG = "AudioPlayer";
|
// AudioPlayer modes
|
||||||
|
public enum MODE { NONE, PLAY, RECORD };
|
||||||
|
|
||||||
// AudioPlayer states
|
// AudioPlayer states
|
||||||
public static int MEDIA_NONE = 0;
|
public enum STATE { MEDIA_NONE,
|
||||||
public static int MEDIA_STARTING = 1;
|
MEDIA_STARTING,
|
||||||
public static int MEDIA_RUNNING = 2;
|
MEDIA_RUNNING,
|
||||||
public static int MEDIA_PAUSED = 3;
|
MEDIA_PAUSED,
|
||||||
public static int MEDIA_STOPPED = 4;
|
MEDIA_STOPPED,
|
||||||
|
MEDIA_LOADING
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final String LOG_TAG = "AudioPlayer";
|
||||||
|
|
||||||
// AudioPlayer message ids
|
// AudioPlayer message ids
|
||||||
private static int MEDIA_STATE = 1;
|
private static int MEDIA_STATE = 1;
|
||||||
@@ -64,47 +69,53 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
private static int MEDIA_ERR_DECODE = 3;
|
private static int MEDIA_ERR_DECODE = 3;
|
||||||
private static int MEDIA_ERR_NONE_SUPPORTED = 4;
|
private static int MEDIA_ERR_NONE_SUPPORTED = 4;
|
||||||
|
|
||||||
private AudioHandler handler; // The AudioHandler object
|
private AudioHandler handler; // The AudioHandler object
|
||||||
private String id; // The id of this player (used to identify Media object in JavaScript)
|
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 MODE mode = MODE.NONE; // Playback or Recording mode
|
||||||
private String audioFile = null; // File name to play or record to
|
private STATE state = STATE.MEDIA_NONE; // State of recording or playback
|
||||||
private float duration = -1; // Duration of audio
|
|
||||||
|
|
||||||
private MediaRecorder recorder = null; // Audio recording object
|
private String audioFile = null; // File name to play or record to
|
||||||
private String tempFile = null; // Temporary recording file name
|
private float duration = -1; // Duration of audio
|
||||||
|
|
||||||
private MediaPlayer mPlayer = null; // Audio player object
|
private MediaRecorder recorder = null; // Audio recording object
|
||||||
private boolean prepareOnly = false;
|
private String tempFile = null; // Temporary recording file name
|
||||||
|
|
||||||
|
private MediaPlayer player = null; // Audio player object
|
||||||
|
private boolean prepareOnly = true; // playback after file prepare flag
|
||||||
|
private int seekOnPrepared = 0; // seek to this location once media is prepared
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param handler The audio handler object
|
* @param handler The audio handler object
|
||||||
* @param id The id of this audio player
|
* @param id The id of this audio player
|
||||||
*/
|
*/
|
||||||
public AudioPlayer(AudioHandler handler, String id) {
|
public AudioPlayer(AudioHandler handler, String id, String file) {
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
this.audioFile = file;
|
||||||
|
this.recorder = new MediaRecorder();
|
||||||
|
|
||||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||||
this.tempFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmprecording.mp3";
|
this.tempFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmprecording.3gp";
|
||||||
} else {
|
} else {
|
||||||
this.tempFile = "/data/data/" + handler.ctx.getPackageName() + "/cache/tmprecording.mp3";
|
this.tempFile = "/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/tmprecording.3gp";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy player and stop audio playing or recording.
|
* Destroy player and stop audio playing or recording.
|
||||||
*/
|
*/
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
|
||||||
// Stop any play or record
|
// Stop any play or record
|
||||||
if (this.mPlayer != null) {
|
if (this.player != null) {
|
||||||
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
|
if ((this.state == STATE.MEDIA_RUNNING) || (this.state == STATE.MEDIA_PAUSED)) {
|
||||||
this.mPlayer.stop();
|
this.player.stop();
|
||||||
this.setState(MEDIA_STOPPED);
|
this.setState(STATE.MEDIA_STOPPED);
|
||||||
}
|
}
|
||||||
this.mPlayer.release();
|
this.player.release();
|
||||||
this.mPlayer = null;
|
this.player = null;
|
||||||
}
|
}
|
||||||
if (this.recorder != null) {
|
if (this.recorder != null) {
|
||||||
this.stopRecording();
|
this.stopRecording();
|
||||||
@@ -116,18 +127,16 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
/**
|
/**
|
||||||
* Start recording the specified file.
|
* Start recording the specified file.
|
||||||
*
|
*
|
||||||
* @param file The name of the file
|
* @param file The name of the file
|
||||||
*/
|
*/
|
||||||
public void startRecording(String file) {
|
public void startRecording(String file) {
|
||||||
if (this.mPlayer != null) {
|
switch (this.mode) {
|
||||||
|
case PLAY:
|
||||||
Log.d(LOG_TAG, "AudioPlayer Error: Can't record in play mode.");
|
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+"});");
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||||
}
|
break;
|
||||||
|
case NONE:
|
||||||
// Make sure we're not already recording
|
|
||||||
else if (this.recorder == null) {
|
|
||||||
this.audioFile = file;
|
this.audioFile = file;
|
||||||
this.recorder = new MediaRecorder();
|
|
||||||
this.recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
|
this.recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
|
||||||
this.recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); // THREE_GPP);
|
this.recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); // THREE_GPP);
|
||||||
this.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //AMR_NB);
|
this.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //AMR_NB);
|
||||||
@@ -135,18 +144,18 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
try {
|
try {
|
||||||
this.recorder.prepare();
|
this.recorder.prepare();
|
||||||
this.recorder.start();
|
this.recorder.start();
|
||||||
this.setState(MEDIA_RUNNING);
|
this.setState(STATE.MEDIA_RUNNING);
|
||||||
return;
|
return;
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||||
}
|
break;
|
||||||
else {
|
case RECORD:
|
||||||
Log.d(LOG_TAG, "AudioPlayer Error: Already recording.");
|
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+"});");
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +171,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
f.renameTo(new File(Environment.getExternalStorageDirectory().getAbsolutePath()
|
f.renameTo(new File(Environment.getExternalStorageDirectory().getAbsolutePath()
|
||||||
+ File.separator + file));
|
+ File.separator + file));
|
||||||
} else {
|
} else {
|
||||||
f.renameTo(new File("/data/data/" + handler.ctx.getPackageName() + "/cache/" + file));
|
f.renameTo(new File("/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/" + file));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -173,10 +182,11 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
public void stopRecording() {
|
public void stopRecording() {
|
||||||
if (this.recorder != null) {
|
if (this.recorder != null) {
|
||||||
try{
|
try{
|
||||||
if (this.state == MEDIA_RUNNING) {
|
if (this.state == STATE.MEDIA_RUNNING) {
|
||||||
this.recorder.stop();
|
this.recorder.stop();
|
||||||
this.setState(MEDIA_STOPPED);
|
this.setState(STATE.MEDIA_STOPPED);
|
||||||
}
|
}
|
||||||
|
this.recorder.reset();
|
||||||
this.moveFile(this.audioFile);
|
this.moveFile(this.audioFile);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
@@ -185,82 +195,22 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
// Playback
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start or resume playing audio file.
|
* 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) {
|
public void startPlaying(String file) {
|
||||||
if (this.recorder != null) {
|
if (this.readyPlayer(file) && this.player != null) {
|
||||||
Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode.");
|
this.player.start();
|
||||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
this.setState(STATE.MEDIA_RUNNING);
|
||||||
}
|
this.seekOnPrepared = 0; //insures this is always reset
|
||||||
|
} else {
|
||||||
// If this is a new request to play audio, or stopped
|
this.prepareOnly = false;
|
||||||
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());
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
|
|
||||||
// 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+"});");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,10 +218,13 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
* Seek or jump to a new time in the track.
|
* Seek or jump to a new time in the track.
|
||||||
*/
|
*/
|
||||||
public void seekToPlaying(int milliseconds) {
|
public void seekToPlaying(int milliseconds) {
|
||||||
if (this.mPlayer != null) {
|
if (this.readyPlayer(this.audioFile)) {
|
||||||
this.mPlayer.seekTo(milliseconds);
|
this.player.seekTo(milliseconds);
|
||||||
Log.d(LOG_TAG, "Send a onStatus update for the new seek");
|
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+");");
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + milliseconds / 1000.0f + ");");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.seekOnPrepared = milliseconds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,13 +234,13 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
public void pausePlaying() {
|
public void pausePlaying() {
|
||||||
|
|
||||||
// If playing, then pause
|
// If playing, then pause
|
||||||
if (this.state == MEDIA_RUNNING) {
|
if (this.state == STATE.MEDIA_RUNNING && this.player != null) {
|
||||||
this.mPlayer.pause();
|
this.player.pause();
|
||||||
this.setState(MEDIA_PAUSED);
|
this.setState(STATE.MEDIA_PAUSED);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: "+this.state);
|
Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: " + this.state.ordinal());
|
||||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_NONE_ACTIVE+"});");
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,34 +248,37 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
* Stop playing the audio file.
|
* Stop playing the audio file.
|
||||||
*/
|
*/
|
||||||
public void stopPlaying() {
|
public void stopPlaying() {
|
||||||
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
|
if ((this.state == STATE.MEDIA_RUNNING) || (this.state == STATE.MEDIA_PAUSED)) {
|
||||||
this.mPlayer.stop();
|
this.player.pause();
|
||||||
this.setState(MEDIA_STOPPED);
|
this.player.seekTo(0);
|
||||||
|
Log.d(LOG_TAG, "stopPlaying is calling stopped");
|
||||||
|
this.setState(STATE.MEDIA_STOPPED);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: "+this.state);
|
Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: " + this.state.ordinal());
|
||||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_NONE_ACTIVE+"});");
|
this.handler.webView.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.
|
* Callback to be invoked when playback of a media source has completed.
|
||||||
*
|
*
|
||||||
* @param mPlayer The MediaPlayer that reached the end of the file
|
* @param player The MediaPlayer that reached the end of the file
|
||||||
*/
|
*/
|
||||||
public void onCompletion(MediaPlayer mPlayer) {
|
public void onCompletion(MediaPlayer player) {
|
||||||
this.setState(MEDIA_STOPPED);
|
Log.d(LOG_TAG, "on completion is calling stopped");
|
||||||
|
this.setState(STATE.MEDIA_STOPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current position of playback.
|
* 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() {
|
public long getCurrentPosition() {
|
||||||
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
|
if ((this.state == STATE.MEDIA_RUNNING) || (this.state == STATE.MEDIA_PAUSED)) {
|
||||||
int curPos = this.mPlayer.getCurrentPosition();
|
int curPos = this.player.getCurrentPosition();
|
||||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_POSITION+", "+curPos/1000.0f+");");
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + curPos / 1000.0f + ");");
|
||||||
return curPos;
|
return curPos;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -334,8 +290,8 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
* Determine if playback file is streaming or local.
|
* Determine if playback file is streaming or local.
|
||||||
* It is streaming if file name starts with "http://"
|
* It is streaming if file name starts with "http://"
|
||||||
*
|
*
|
||||||
* @param file The file name
|
* @param file The file name
|
||||||
* @return T=streaming, F=local
|
* @return T=streaming, F=local
|
||||||
*/
|
*/
|
||||||
public boolean isStreaming(String file) {
|
public boolean isStreaming(String file) {
|
||||||
if (file.contains("http://") || file.contains("https://")) {
|
if (file.contains("http://") || file.contains("https://")) {
|
||||||
@@ -346,23 +302,23 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the duration of the audio file.
|
* Get the duration of the audio file.
|
||||||
*
|
*
|
||||||
* @param file The name of the audio file.
|
* @param file The name of the audio file.
|
||||||
* @return The duration in msec.
|
* @return The duration in msec.
|
||||||
* -1=can't be determined
|
* -1=can't be determined
|
||||||
* -2=not allowed
|
* -2=not allowed
|
||||||
*/
|
*/
|
||||||
public float getDuration(String file) {
|
public float getDuration(String file) {
|
||||||
|
|
||||||
// Can't get duration of recording
|
// Can't get duration of recording
|
||||||
if (this.recorder != null) {
|
if (this.recorder != null) {
|
||||||
return(-2); // not allowed
|
return (-2); // not allowed
|
||||||
}
|
}
|
||||||
|
|
||||||
// If audio file already loaded and started, then return duration
|
// If audio file already loaded and started, then return duration
|
||||||
if (this.mPlayer != null) {
|
if (this.player != null) {
|
||||||
return this.duration;
|
return this.duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,29 +336,28 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
/**
|
/**
|
||||||
* Callback to be invoked when the media source is ready for playback.
|
* Callback to be invoked when the media source is ready for playback.
|
||||||
*
|
*
|
||||||
* @param mPlayer The MediaPlayer that is ready for playback
|
* @param player The MediaPlayer that is ready for playback
|
||||||
*/
|
*/
|
||||||
public void onPrepared(MediaPlayer mPlayer) {
|
public void onPrepared(MediaPlayer player) {
|
||||||
// Listen for playback completion
|
// Listen for playback completion
|
||||||
this.mPlayer.setOnCompletionListener(this);
|
this.player.setOnCompletionListener(this);
|
||||||
|
// seek to any location received while not prepared
|
||||||
|
this.seekToPlaying(this.seekOnPrepared);
|
||||||
// If start playing after prepared
|
// If start playing after prepared
|
||||||
if (!this.prepareOnly) {
|
if (!this.prepareOnly) {
|
||||||
|
this.player.start();
|
||||||
// Start playing
|
this.setState(STATE.MEDIA_RUNNING);
|
||||||
this.mPlayer.start();
|
this.seekOnPrepared = 0; //reset only when played
|
||||||
|
} else {
|
||||||
// Set player init flag
|
this.setState(STATE.MEDIA_STARTING);
|
||||||
this.setState(MEDIA_RUNNING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save off duration
|
// Save off duration
|
||||||
this.duration = getDurationInSeconds();
|
this.duration = getDurationInSeconds();
|
||||||
this.prepareOnly = false;
|
// reset prepare only flag
|
||||||
|
this.prepareOnly = true;
|
||||||
|
|
||||||
// Send status notification to JavaScript
|
// Send status notification to JavaScript
|
||||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_DURATION+","+this.duration+");");
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_DURATION + "," + this.duration + ");");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -411,26 +366,26 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
* @return length of clip in seconds
|
* @return length of clip in seconds
|
||||||
*/
|
*/
|
||||||
private float getDurationInSeconds() {
|
private float getDurationInSeconds() {
|
||||||
return (this.mPlayer.getDuration() / 1000.0f);
|
return (this.player.getDuration() / 1000.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback to be invoked when there has been an error during an asynchronous operation
|
* Callback to be invoked when there has been an error during an asynchronous operation
|
||||||
* (other errors will throw exceptions at method call time).
|
* (other errors will throw exceptions at method call time).
|
||||||
*
|
*
|
||||||
* @param mPlayer the MediaPlayer the error pertains to
|
* @param player the MediaPlayer the error pertains to
|
||||||
* @param arg1 the type of error that has occurred: (MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_SERVER_DIED)
|
* @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.
|
* @param arg2 an extra code, specific to the error.
|
||||||
*/
|
*/
|
||||||
public boolean onError(MediaPlayer mPlayer, int arg1, int arg2) {
|
public boolean onError(MediaPlayer player, int arg1, int arg2) {
|
||||||
Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2+")");
|
Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2 + ")");
|
||||||
|
|
||||||
// TODO: Not sure if this needs to be sent?
|
// TODO: Not sure if this needs to be sent?
|
||||||
this.mPlayer.stop();
|
this.player.stop();
|
||||||
this.mPlayer.release();
|
this.player.release();
|
||||||
|
|
||||||
// Send error notification to JavaScript
|
// Send error notification to JavaScript
|
||||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', { \"code\":"+arg1+"});");
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', { \"code\":" + arg1 + "});");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,21 +394,33 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
*
|
*
|
||||||
* @param state
|
* @param state
|
||||||
*/
|
*/
|
||||||
private void setState(int state) {
|
private void setState(STATE state) {
|
||||||
if (this.state != state) {
|
if (this.state != state) {
|
||||||
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_STATE+", "+state+");");
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_STATE + ", " + state.ordinal() + ");");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.state = state;
|
this.state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the mode and send it to JavaScript.
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
*/
|
||||||
|
private void setMode(MODE mode) {
|
||||||
|
if (this.mode != mode) {
|
||||||
|
//mode is not part of the expected behavior, so no notification
|
||||||
|
//this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_STATE + ", " + mode + ");");
|
||||||
|
}
|
||||||
|
this.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the audio state.
|
* Get the audio state.
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public int getState() {
|
public int getState() {
|
||||||
return this.state;
|
return this.state.ordinal();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -462,6 +429,120 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
|
|||||||
* @param volume
|
* @param volume
|
||||||
*/
|
*/
|
||||||
public void setVolume(float volume) {
|
public void setVolume(float volume) {
|
||||||
this.mPlayer.setVolume(volume, volume);
|
this.player.setVolume(volume, volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* attempts to put the player in play mode
|
||||||
|
* @return true if in playmode, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean playMode() {
|
||||||
|
switch(this.mode) {
|
||||||
|
case NONE:
|
||||||
|
this.setMode(MODE.PLAY);
|
||||||
|
break;
|
||||||
|
case PLAY:
|
||||||
|
break;
|
||||||
|
case RECORD:
|
||||||
|
Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode.");
|
||||||
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
|
||||||
|
return false; //player is not ready
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* attempts to initialize the media player for playback
|
||||||
|
* @param file the file to play
|
||||||
|
* @return false if player not ready, reports if in wrong mode or state
|
||||||
|
*/
|
||||||
|
private boolean readyPlayer(String file) {
|
||||||
|
if (playMode()) {
|
||||||
|
switch (this.state) {
|
||||||
|
case MEDIA_NONE:
|
||||||
|
if (this.player == null) {
|
||||||
|
this.player = new MediaPlayer();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.loadAudioFile(file);
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case MEDIA_LOADING:
|
||||||
|
//cordova js is not aware of MEDIA_LOADING, so we send MEDIA_STARTING instead
|
||||||
|
Log.d(LOG_TAG, "AudioPlayer Loading: startPlaying() called during media preparation: " + STATE.MEDIA_STARTING.ordinal());
|
||||||
|
this.prepareOnly = false;
|
||||||
|
return false;
|
||||||
|
case MEDIA_STARTING:
|
||||||
|
case MEDIA_RUNNING:
|
||||||
|
case MEDIA_PAUSED:
|
||||||
|
return true;
|
||||||
|
case MEDIA_STOPPED:
|
||||||
|
//if we are readying the same file
|
||||||
|
if (this.audioFile.compareTo(file) == 0) {
|
||||||
|
//reset the audio file
|
||||||
|
player.seekTo(0);
|
||||||
|
player.pause();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
//reset the player
|
||||||
|
this.player.reset();
|
||||||
|
try {
|
||||||
|
this.loadAudioFile(file);
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
|
||||||
|
}
|
||||||
|
//if we had to prepare= the file, we won't be in the correct state for playback
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Log.d(LOG_TAG, "AudioPlayer Error: startPlaying() called during invalid state: " + this.state);
|
||||||
|
this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load audio file
|
||||||
|
* @throws IOException
|
||||||
|
* @throws IllegalStateException
|
||||||
|
* @throws SecurityException
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
*/
|
||||||
|
private void loadAudioFile(String file) throws IllegalArgumentException, SecurityException, IllegalStateException, IOException {
|
||||||
|
if (this.isStreaming(file)) {
|
||||||
|
this.player.setDataSource(file);
|
||||||
|
this.player.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||||
|
//if it's a streaming file, play mode is implied
|
||||||
|
this.setMode(MODE.PLAY);
|
||||||
|
this.setState(STATE.MEDIA_STARTING);
|
||||||
|
this.player.setOnPreparedListener(this);
|
||||||
|
this.player.prepareAsync();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (file.startsWith("/android_asset/")) {
|
||||||
|
String f = file.substring(15);
|
||||||
|
android.content.res.AssetFileDescriptor fd = this.handler.cordova.getActivity().getAssets().openFd(f);
|
||||||
|
this.player.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
File fp = new File(file);
|
||||||
|
if (fp.exists()) {
|
||||||
|
FileInputStream fileInputStream = new FileInputStream(file);
|
||||||
|
this.player.setDataSource(fileInputStream.getFD());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.player.setDataSource("/sdcard/" + file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState(STATE.MEDIA_STARTING);
|
||||||
|
this.player.setOnPreparedListener(this);
|
||||||
|
this.player.prepare();
|
||||||
|
|
||||||
|
// Get duration
|
||||||
|
this.duration = getDurationInSeconds();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,26 +18,26 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.cordova;
|
package org.apache.cordova;
|
||||||
|
|
||||||
import org.apache.cordova.api.Plugin;
|
import org.apache.cordova.api.CallbackContext;
|
||||||
|
import org.apache.cordova.api.CordovaPlugin;
|
||||||
import org.apache.cordova.api.PluginResult;
|
import org.apache.cordova.api.PluginResult;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class BatteryListener extends Plugin {
|
public class BatteryListener extends CordovaPlugin {
|
||||||
|
|
||||||
private static final String LOG_TAG = "BatteryManager";
|
private static final String LOG_TAG = "BatteryManager";
|
||||||
|
|
||||||
BroadcastReceiver receiver;
|
BroadcastReceiver receiver;
|
||||||
|
|
||||||
private String batteryCallbackId = null;
|
private CallbackContext batteryCallbackContext = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@@ -47,25 +47,23 @@ public class BatteryListener extends Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the request and returns PluginResult.
|
* Executes the request.
|
||||||
*
|
*
|
||||||
* @param action The action to execute.
|
* @param action The action to execute.
|
||||||
* @param args JSONArry of arguments for the plugin.
|
* @param args JSONArry of arguments for the plugin.
|
||||||
* @param callbackId The callback id used when calling back into JavaScript.
|
* @param callbackContext The callback context used when calling back into JavaScript.
|
||||||
* @return A PluginResult object with a status and message.
|
* @return True if the action was valid, false if not.
|
||||||
*/
|
*/
|
||||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
|
||||||
PluginResult.Status status = PluginResult.Status.INVALID_ACTION;
|
|
||||||
String result = "Unsupported Operation: " + action;
|
|
||||||
|
|
||||||
if (action.equals("start")) {
|
if (action.equals("start")) {
|
||||||
if (this.batteryCallbackId != null) {
|
if (this.batteryCallbackContext != null) {
|
||||||
return new PluginResult(PluginResult.Status.ERROR, "Battery listener already running.");
|
callbackContext.error( "Battery listener already running.");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
this.batteryCallbackId = callbackId;
|
this.batteryCallbackContext = callbackContext;
|
||||||
|
|
||||||
// We need to listen to power events to update battery status
|
// 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);
|
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||||
if (this.receiver == null) {
|
if (this.receiver == null) {
|
||||||
this.receiver = new BroadcastReceiver() {
|
this.receiver = new BroadcastReceiver() {
|
||||||
@@ -74,23 +72,25 @@ public class BatteryListener extends Plugin {
|
|||||||
updateBatteryInfo(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 pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||||
pluginResult.setKeepCallback(true);
|
pluginResult.setKeepCallback(true);
|
||||||
return pluginResult;
|
callbackContext.sendPluginResult(pluginResult);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (action.equals("stop")) {
|
else if (action.equals("stop")) {
|
||||||
removeBatteryListener();
|
removeBatteryListener();
|
||||||
this.sendUpdate(new JSONObject(), false); // release status callback in JS side
|
this.sendUpdate(new JSONObject(), false); // release status callback in JS side
|
||||||
this.batteryCallbackId = null;
|
this.batteryCallbackContext = null;
|
||||||
return new PluginResult(PluginResult.Status.OK);
|
callbackContext.success();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PluginResult(status, result);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,13 +100,20 @@ public class BatteryListener extends Plugin {
|
|||||||
removeBatteryListener();
|
removeBatteryListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop battery receiver.
|
||||||
|
*/
|
||||||
|
public void onReset() {
|
||||||
|
removeBatteryListener();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop the battery receiver and set it to null.
|
* Stop the battery receiver and set it to null.
|
||||||
*/
|
*/
|
||||||
private void removeBatteryListener() {
|
private void removeBatteryListener() {
|
||||||
if (this.receiver != null) {
|
if (this.receiver != null) {
|
||||||
try {
|
try {
|
||||||
this.ctx.unregisterReceiver(this.receiver);
|
this.cordova.getActivity().unregisterReceiver(this.receiver);
|
||||||
this.receiver = null;
|
this.receiver = null;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(LOG_TAG, "Error unregistering battery receiver: " + e.getMessage(), e);
|
Log.e(LOG_TAG, "Error unregistering battery receiver: " + e.getMessage(), e);
|
||||||
@@ -147,10 +154,10 @@ public class BatteryListener extends Plugin {
|
|||||||
* @param connection the network info to set as navigator.connection
|
* @param connection the network info to set as navigator.connection
|
||||||
*/
|
*/
|
||||||
private void sendUpdate(JSONObject info, boolean keepCallback) {
|
private void sendUpdate(JSONObject info, boolean keepCallback) {
|
||||||
if (this.batteryCallbackId != null) {
|
if (this.batteryCallbackContext != null) {
|
||||||
PluginResult result = new PluginResult(PluginResult.Status.OK, info);
|
PluginResult result = new PluginResult(PluginResult.Status.OK, info);
|
||||||
result.setKeepCallback(keepCallback);
|
result.setKeepCallback(keepCallback);
|
||||||
this.success(result, this.batteryCallbackId);
|
this.batteryCallbackContext.sendPluginResult(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,428 +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.io.BufferedReader;
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
* 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().
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
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>();
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restart the server on a new thread.
|
|
||||||
*/
|
|
||||||
public void restartServer() {
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
//System.out.println("CallbackServer -- using port " +this.port);
|
|
||||||
this.token = java.util.UUID.randomUUID().toString();
|
|
||||||
//System.out.println("CallbackServer -- using token "+this.token);
|
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
// 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) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If server is still running
|
|
||||||
if (this.active) {
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// Break out of server wait
|
|
||||||
synchronized (this) {
|
|
||||||
this.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy
|
|
||||||
*/
|
|
||||||
public void destroy() {
|
|
||||||
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 */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
* 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 {
|
|
||||||
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;
|
|
||||||
for (int i = 0; i < s.length(); i++) {
|
|
||||||
char ch = s.charAt(i);
|
|
||||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|
|
||||||
|| (ch >= '0' && ch <= '9')
|
|
||||||
|| " .-*_'(),<>=?@[]{}:~\"\\/;!".indexOf(ch) > -1) {
|
|
||||||
if (start >= 0) {
|
|
||||||
convert(s.substring(start, i), buf, enc);
|
|
||||||
start = -1;
|
|
||||||
}
|
|
||||||
if (ch != ' ') {
|
|
||||||
buf.append(ch);
|
|
||||||
} else {
|
|
||||||
buf.append(' ');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (start < 0) {
|
|
||||||
start = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start >= 0) {
|
|
||||||
convert(s.substring(start, s.length()), buf, enc);
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void convert(String s, StringBuilder buf, String enc) throws UnsupportedEncodingException {
|
|
||||||
byte[] bytes = s.getBytes(enc);
|
|
||||||
for (int j = 0; j < bytes.length; j++) {
|
|
||||||
buf.append('%');
|
|
||||||
buf.append(digits.charAt((bytes[j] & 0xf0) >> 4));
|
|
||||||
buf.append(digits.charAt(bytes[j] & 0xf));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* end */
|
|
||||||
}
|
|
||||||
@@ -20,14 +20,16 @@ package org.apache.cordova;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
import org.apache.cordova.api.CallbackContext;
|
||||||
|
import org.apache.cordova.api.CordovaPlugin;
|
||||||
import org.apache.cordova.api.LOG;
|
import org.apache.cordova.api.LOG;
|
||||||
import org.apache.cordova.api.Plugin;
|
|
||||||
import org.apache.cordova.api.PluginResult;
|
import org.apache.cordova.api.PluginResult;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
@@ -37,17 +39,22 @@ import android.content.ContentValues;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Bitmap.CompressFormat;
|
import android.graphics.Bitmap.CompressFormat;
|
||||||
|
import android.media.MediaScannerConnection;
|
||||||
|
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Environment;
|
||||||
import android.provider.MediaStore;
|
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,
|
* 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.
|
* the camera view was shown is redisplayed.
|
||||||
*/
|
*/
|
||||||
public class CameraLauncher extends Plugin {
|
public class CameraLauncher extends CordovaPlugin implements MediaScannerConnectionClient {
|
||||||
|
|
||||||
private static final int DATA_URL = 0; // Return base64 encoded string
|
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 FILE_URI = 1; // Return file uri (content://media/external/images/media/2 for Android)
|
||||||
@@ -74,62 +81,86 @@ public class CameraLauncher extends Plugin {
|
|||||||
private Uri imageUri; // Uri of captured image
|
private Uri imageUri; // Uri of captured image
|
||||||
private int encodingType; // Type of encoding to use
|
private int encodingType; // Type of encoding to use
|
||||||
private int mediaType; // What type of media to retrieve
|
private int mediaType; // What type of media to retrieve
|
||||||
|
private boolean saveToPhotoAlbum; // Should the picture be saved to the device's photo album
|
||||||
|
private boolean correctOrientation; // Should the pictures orientation be corrected
|
||||||
|
//private boolean allowEdit; // Should we allow the user to crop the image. UNUSED.
|
||||||
|
|
||||||
public String callbackId;
|
public CallbackContext callbackContext;
|
||||||
private int numPics;
|
private int numPics;
|
||||||
|
|
||||||
|
private MediaScannerConnection conn; // Used to update gallery app with newly-written files
|
||||||
|
private Uri scanMe; // Uri of image to be added to content store
|
||||||
|
|
||||||
|
//This should never be null!
|
||||||
|
//private CordovaInterface cordova;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
public CameraLauncher() {
|
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.
|
* Executes the request and returns PluginResult.
|
||||||
*
|
*
|
||||||
* @param action The action to execute.
|
* @param action The action to execute.
|
||||||
* @param args JSONArry of arguments for the plugin.
|
* @param args JSONArry of arguments for the plugin.
|
||||||
* @param callbackId The callback id used when calling back into JavaScript.
|
* @param callbackContext The callback id used when calling back into JavaScript.
|
||||||
* @return A PluginResult object with a status and message.
|
* @return A PluginResult object with a status and message.
|
||||||
*/
|
*/
|
||||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||||
PluginResult.Status status = PluginResult.Status.OK;
|
this.callbackContext = callbackContext;
|
||||||
String result = "";
|
|
||||||
this.callbackId = callbackId;
|
|
||||||
|
|
||||||
try {
|
if (action.equals("takePicture")) {
|
||||||
if (action.equals("takePicture")) {
|
int srcType = CAMERA;
|
||||||
int srcType = CAMERA;
|
int destType = FILE_URI;
|
||||||
int destType = FILE_URI;
|
this.saveToPhotoAlbum = false;
|
||||||
this.targetHeight = 0;
|
this.targetHeight = 0;
|
||||||
this.targetWidth = 0;
|
this.targetWidth = 0;
|
||||||
this.encodingType = JPEG;
|
this.encodingType = JPEG;
|
||||||
this.mediaType = PICTURE;
|
this.mediaType = PICTURE;
|
||||||
this.mQuality = 80;
|
this.mQuality = 80;
|
||||||
|
|
||||||
this.mQuality = args.getInt(0);
|
this.mQuality = args.getInt(0);
|
||||||
destType = args.getInt(1);
|
destType = args.getInt(1);
|
||||||
srcType = args.getInt(2);
|
srcType = args.getInt(2);
|
||||||
this.targetWidth = args.getInt(3);
|
this.targetWidth = args.getInt(3);
|
||||||
this.targetHeight = args.getInt(4);
|
this.targetHeight = args.getInt(4);
|
||||||
this.encodingType = args.getInt(5);
|
this.encodingType = args.getInt(5);
|
||||||
this.mediaType = args.getInt(6);
|
this.mediaType = args.getInt(6);
|
||||||
|
//this.allowEdit = args.getBoolean(7); // This field is unused.
|
||||||
|
this.correctOrientation = args.getBoolean(8);
|
||||||
|
this.saveToPhotoAlbum = args.getBoolean(9);
|
||||||
|
|
||||||
if (srcType == CAMERA) {
|
// If the user specifies a 0 or smaller width/height
|
||||||
this.takePicture(destType, encodingType);
|
// make it -1 so later comparisons succeed
|
||||||
}
|
if (this.targetWidth < 1) {
|
||||||
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
|
this.targetWidth = -1;
|
||||||
this.getImage(srcType, destType);
|
|
||||||
}
|
|
||||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
|
||||||
r.setKeepCallback(true);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
return new PluginResult(status, result);
|
if (this.targetHeight < 1) {
|
||||||
} catch (JSONException e) {
|
this.targetHeight = -1;
|
||||||
e.printStackTrace();
|
}
|
||||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
|
||||||
|
if (srcType == CAMERA) {
|
||||||
|
this.takePicture(destType, encodingType);
|
||||||
|
}
|
||||||
|
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
|
||||||
|
this.getImage(srcType, destType);
|
||||||
|
}
|
||||||
|
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
||||||
|
r.setKeepCallback(true);
|
||||||
|
callbackContext.sendPluginResult(r);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
@@ -152,18 +183,21 @@ public class CameraLauncher extends Plugin {
|
|||||||
*/
|
*/
|
||||||
public void takePicture(int returnType, int encodingType) {
|
public void takePicture(int returnType, int encodingType) {
|
||||||
// Save the number of images currently on disk for later
|
// Save the number of images currently on disk for later
|
||||||
this.numPics = queryImgDB().getCount();
|
this.numPics = queryImgDB(whichContentStore()).getCount();
|
||||||
|
|
||||||
// Display camera
|
// Display camera
|
||||||
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
|
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
|
||||||
|
|
||||||
// Specify file so that large image is captured and returned
|
// Specify file so that large image is captured and returned
|
||||||
// TODO: What if there isn't any external storage?
|
|
||||||
File photo = createCaptureFile(encodingType);
|
File photo = createCaptureFile(encodingType);
|
||||||
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
|
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
|
||||||
this.imageUri = 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((CordovaPlugin) 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -175,9 +209,9 @@ public class CameraLauncher extends Plugin {
|
|||||||
private File createCaptureFile(int encodingType) {
|
private File createCaptureFile(int encodingType) {
|
||||||
File photo = null;
|
File photo = null;
|
||||||
if (encodingType == JPEG) {
|
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) {
|
} else if (encodingType == PNG) {
|
||||||
photo = new File(DirectoryManager.getTempDirectoryPath(ctx.getContext()), "Pic.png");
|
photo = new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), ".Pic.png");
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Invalid Encoding Type: " + encodingType);
|
throw new IllegalArgumentException("Invalid Encoding Type: " + encodingType);
|
||||||
}
|
}
|
||||||
@@ -211,54 +245,10 @@ public class CameraLauncher extends Plugin {
|
|||||||
|
|
||||||
intent.setAction(Intent.ACTION_GET_CONTENT);
|
intent.setAction(Intent.ACTION_GET_CONTENT);
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
this.ctx.startActivityForResult((Plugin) this, Intent.createChooser(intent,
|
if (this.cordova != null) {
|
||||||
new String(title)), (srcType+1)*16 + returnType + 1);
|
this.cordova.startActivityForResult((CordovaPlugin) 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.
|
|
||||||
*/
|
|
||||||
public Bitmap scaleBitmap(Bitmap bitmap) {
|
|
||||||
int newWidth = this.targetWidth;
|
|
||||||
int newHeight = this.targetHeight;
|
|
||||||
int origWidth = bitmap.getWidth();
|
|
||||||
int origHeight = bitmap.getHeight();
|
|
||||||
|
|
||||||
// If no new width or height were specified return the original bitmap
|
|
||||||
if (newWidth <= 0 && newHeight <= 0) {
|
|
||||||
return bitmap;
|
|
||||||
}
|
}
|
||||||
// Only the width was specified
|
|
||||||
else if (newWidth > 0 && newHeight <= 0) {
|
|
||||||
newHeight = (newWidth * origHeight) / origWidth;
|
|
||||||
}
|
|
||||||
// only the height was specified
|
|
||||||
else if (newWidth <= 0 && newHeight > 0) {
|
|
||||||
newWidth = (newHeight * origWidth) / origHeight;
|
|
||||||
}
|
|
||||||
// If the user specified both a positive width and height
|
|
||||||
// (potentially different aspect ratio) then the width or height is
|
|
||||||
// scaled so that the image fits while maintaining aspect ratio.
|
|
||||||
// Alternatively, the specified width and height could have been
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
if (origRatio > newRatio) {
|
|
||||||
newHeight = (newWidth * origHeight) / origWidth;
|
|
||||||
} else if (origRatio < newRatio) {
|
|
||||||
newWidth = (newHeight * origWidth) / origHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitmap retval = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
|
|
||||||
bitmap.recycle();
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -272,83 +262,102 @@ public class CameraLauncher extends Plugin {
|
|||||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||||
|
|
||||||
// Get src and dest types from request code
|
// Get src and dest types from request code
|
||||||
int srcType = (requestCode/16) - 1;
|
int srcType = (requestCode / 16) - 1;
|
||||||
int destType = (requestCode % 16) - 1;
|
int destType = (requestCode % 16) - 1;
|
||||||
int rotate = 0;
|
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If CAMERA
|
// If CAMERA
|
||||||
if (srcType == CAMERA) {
|
if (srcType == CAMERA) {
|
||||||
// If image available
|
// If image available
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
try {
|
try {
|
||||||
// Read in bitmap of captured image
|
// Create an ExifHelper to save the exif data that is lost during compression
|
||||||
Bitmap bitmap;
|
ExifHelper exif = new ExifHelper();
|
||||||
try {
|
try {
|
||||||
bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
|
if (this.encodingType == JPEG) {
|
||||||
} catch (FileNotFoundException e) {
|
exif.createInFile(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/.Pic.jpg");
|
||||||
Uri uri = intent.getData();
|
exif.readExifData();
|
||||||
android.content.ContentResolver resolver = this.ctx.getContentResolver();
|
rotate = exif.getOrientation();
|
||||||
bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap = scaleBitmap(bitmap);
|
Bitmap bitmap = null;
|
||||||
|
Uri uri = null;
|
||||||
|
|
||||||
// If sending base64 image back
|
// If sending base64 image back
|
||||||
if (destType == DATA_URL) {
|
if (destType == DATA_URL) {
|
||||||
|
bitmap = getScaledBitmap(FileUtils.stripFileProtocol(imageUri.toString()));
|
||||||
|
if (bitmap == null) {
|
||||||
|
// Try to get the bitmap from intent.
|
||||||
|
bitmap = (Bitmap)intent.getExtras().get("data");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Double-check the bitmap.
|
||||||
|
if (bitmap == null) {
|
||||||
|
Log.d(LOG_TAG, "I either have a null image path or bitmap");
|
||||||
|
this.failPicture("Unable to create bitmap!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rotate != 0 && this.correctOrientation) {
|
||||||
|
bitmap = getRotatedBitmap(rotate, bitmap, exif);
|
||||||
|
}
|
||||||
|
|
||||||
this.processPicture(bitmap);
|
this.processPicture(bitmap);
|
||||||
checkForDuplicateImage(DATA_URL);
|
checkForDuplicateImage(DATA_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If sending filename back
|
// If sending filename back
|
||||||
else if (destType == FILE_URI){
|
else if (destType == FILE_URI) {
|
||||||
// Create entry in media store for image
|
if (!this.saveToPhotoAlbum) {
|
||||||
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
|
uri = Uri.fromFile(new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), System.currentTimeMillis() + ".jpg"));
|
||||||
ContentValues values = new ContentValues();
|
} else {
|
||||||
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
|
uri = getUriFromMediaStore();
|
||||||
Uri uri = null;
|
}
|
||||||
try {
|
|
||||||
uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
if (uri == null) {
|
||||||
} catch (UnsupportedOperationException e) {
|
this.failPicture("Error capturing image - no media storage found.");
|
||||||
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);
|
// If all this is true we shouldn't compress the image.
|
||||||
} catch (UnsupportedOperationException ex) {
|
if (this.targetHeight == -1 && this.targetWidth == -1 && this.mQuality == 100 && rotate == 0) {
|
||||||
LOG.d(LOG_TAG, "Can't write to internal media storage.");
|
writeUncompressedImage(uri);
|
||||||
this.failPicture("Error capturing image - no media storage found.");
|
|
||||||
return;
|
this.callbackContext.success(uri.toString());
|
||||||
|
} else {
|
||||||
|
bitmap = getScaledBitmap(FileUtils.stripFileProtocol(imageUri.toString()));
|
||||||
|
|
||||||
|
if (rotate != 0 && this.correctOrientation) {
|
||||||
|
bitmap = getRotatedBitmap(rotate, bitmap, exif);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send Uri back to JavaScript for viewing image
|
// Send Uri back to JavaScript for viewing image
|
||||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
this.callbackContext.success(uri.toString());
|
||||||
}
|
}
|
||||||
bitmap.recycle();
|
|
||||||
bitmap = null;
|
|
||||||
System.gc();
|
|
||||||
|
|
||||||
checkForDuplicateImage(FILE_URI);
|
this.cleanup(FILE_URI, this.imageUri, uri, bitmap);
|
||||||
|
bitmap = null;
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
this.failPicture("Error capturing image.");
|
this.failPicture("Error capturing image.");
|
||||||
@@ -370,77 +379,104 @@ public class CameraLauncher extends Plugin {
|
|||||||
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
|
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
Uri uri = intent.getData();
|
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
|
// 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
|
// and there will be no attempt to resize any returned data
|
||||||
if (this.mediaType != PICTURE) {
|
if (this.mediaType != PICTURE) {
|
||||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
this.callbackContext.success(uri.toString());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If sending base64 image back
|
// This is a special case to just return the path as no scaling,
|
||||||
if (destType == DATA_URL) {
|
// rotating or compression needs to be done
|
||||||
try {
|
if (this.targetHeight == -1 && this.targetWidth == -1 &&
|
||||||
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
this.mQuality == 100 && destType == FILE_URI && !this.correctOrientation) {
|
||||||
String[] cols = { MediaStore.Images.Media.ORIENTATION };
|
this.callbackContext.success(uri.toString());
|
||||||
Cursor cursor = this.ctx.getContentResolver().query(intent.getData(),
|
} else {
|
||||||
cols,
|
// Get the path to the image. Makes loading so much easier.
|
||||||
null, null, null);
|
String imagePath = FileUtils.getRealPathFromURI(uri, this.cordova);
|
||||||
if (cursor != null) {
|
String mimeType = FileUtils.getMimeType(imagePath);
|
||||||
cursor.moveToPosition(0);
|
// Log.d(LOG_TAG, "Real path = " + imagePath);
|
||||||
rotate = cursor.getInt(0);
|
// Log.d(LOG_TAG, "mime type = " + mimeType);
|
||||||
cursor.close();
|
// If we don't have a valid image so quit.
|
||||||
}
|
if (imagePath == null || mimeType == null ||
|
||||||
if (rotate != 0) {
|
!(mimeType.equalsIgnoreCase("image/jpeg") || mimeType.equalsIgnoreCase("image/png"))) {
|
||||||
Matrix matrix = new Matrix();
|
Log.d(LOG_TAG, "I either have a null image path or bitmap");
|
||||||
matrix.setRotate(rotate);
|
this.failPicture("Unable to retrieve path to picture!");
|
||||||
bitmap = bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
return;
|
||||||
}
|
}
|
||||||
bitmap = scaleBitmap(bitmap);
|
Bitmap bitmap = getScaledBitmap(imagePath);
|
||||||
this.processPicture(bitmap);
|
if (bitmap == null) {
|
||||||
bitmap.recycle();
|
Log.d(LOG_TAG, "I either have a null image path or bitmap");
|
||||||
bitmap = null;
|
this.failPicture("Unable to create bitmap!");
|
||||||
System.gc();
|
return;
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
this.failPicture("Error retrieving image.");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If sending filename back
|
if (this.correctOrientation) {
|
||||||
else if (destType == FILE_URI) {
|
String[] cols = { MediaStore.Images.Media.ORIENTATION };
|
||||||
// Do we need to scale the returned file
|
Cursor cursor = this.cordova.getActivity().getContentResolver().query(intent.getData(),
|
||||||
if (this.targetHeight > 0 && this.targetWidth > 0) {
|
cols, null, null, null);
|
||||||
try {
|
if (cursor != null) {
|
||||||
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
|
cursor.moveToPosition(0);
|
||||||
bitmap = scaleBitmap(bitmap);
|
rotate = cursor.getInt(0);
|
||||||
|
cursor.close();
|
||||||
String fileName = DirectoryManager.getTempDirectoryPath(ctx.getContext()) + "/resize.jpg";
|
}
|
||||||
OutputStream os = new FileOutputStream(fileName);
|
if (rotate != 0) {
|
||||||
bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
|
Matrix matrix = new Matrix();
|
||||||
os.close();
|
matrix.setRotate(rotate);
|
||||||
|
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||||
// Restore exif data to file
|
|
||||||
if (this.encodingType == JPEG) {
|
|
||||||
exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.ctx));
|
|
||||||
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
|
|
||||||
// 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();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
this.failPicture("Error retrieving image.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId);
|
// If sending base64 image back
|
||||||
|
if (destType == DATA_URL) {
|
||||||
|
this.processPicture(bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If sending filename back
|
||||||
|
else if (destType == FILE_URI) {
|
||||||
|
// Do we need to scale the returned file
|
||||||
|
if (this.targetHeight > 0 && this.targetWidth > 0) {
|
||||||
|
try {
|
||||||
|
// Create an ExifHelper to save the exif data that is lost during compression
|
||||||
|
String resizePath = DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/resize.jpg";
|
||||||
|
ExifHelper exif = new ExifHelper();
|
||||||
|
try {
|
||||||
|
if (this.encodingType == JPEG) {
|
||||||
|
exif.createInFile(resizePath);
|
||||||
|
exif.readExifData();
|
||||||
|
rotate = exif.getOrientation();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputStream os = new FileOutputStream(resizePath);
|
||||||
|
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.cordova));
|
||||||
|
exif.writeExifData();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.callbackContext.success("file://" + resizePath + "?" + System.currentTimeMillis());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
this.failPicture("Error retrieving image.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.callbackContext.success(uri.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bitmap != null) {
|
||||||
|
bitmap.recycle();
|
||||||
|
bitmap = null;
|
||||||
|
}
|
||||||
|
System.gc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -453,20 +489,205 @@ public class CameraLauncher extends Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Figure out if the bitmap should be rotated. For instance if the picture was taken in
|
||||||
|
* portrait mode
|
||||||
|
*
|
||||||
|
* @param rotate
|
||||||
|
* @param bitmap
|
||||||
|
* @return rotated bitmap
|
||||||
|
*/
|
||||||
|
private Bitmap getRotatedBitmap(int rotate, Bitmap bitmap, ExifHelper exif) {
|
||||||
|
Matrix matrix = new Matrix();
|
||||||
|
if (rotate == 180) {
|
||||||
|
matrix.setRotate(rotate);
|
||||||
|
} else {
|
||||||
|
matrix.setRotate(rotate, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2);
|
||||||
|
}
|
||||||
|
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||||
|
exif.resetOrientation();
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In the special case where the default width, height and quality are unchanged
|
||||||
|
* we just write the file out to disk saving the expensive Bitmap.compress function.
|
||||||
|
*
|
||||||
|
* @param uri
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void writeUncompressedImage(Uri uri) throws FileNotFoundException,
|
||||||
|
IOException {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create entry in media store for image
|
||||||
|
*
|
||||||
|
* @return uri
|
||||||
|
*/
|
||||||
|
private Uri getUriFromMediaStore() {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
|
||||||
|
Uri uri;
|
||||||
|
try {
|
||||||
|
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.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a scaled bitmap based on the target width and height
|
||||||
|
*
|
||||||
|
* @param imagePath
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Bitmap getScaledBitmap(String imagePath) {
|
||||||
|
// If no new width or height were specified return the original bitmap
|
||||||
|
if (this.targetWidth <= 0 && this.targetHeight <= 0) {
|
||||||
|
return BitmapFactory.decodeFile(imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// figure out the original width and height of the image
|
||||||
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
|
options.inJustDecodeBounds = true;
|
||||||
|
BitmapFactory.decodeFile(imagePath, options);
|
||||||
|
|
||||||
|
// determine the correct aspect ratio
|
||||||
|
int[] widthHeight = calculateAspectRatio(options.outWidth, options.outHeight);
|
||||||
|
|
||||||
|
// Load in the smallest bitmap possible that is closest to the size we want
|
||||||
|
options.inJustDecodeBounds = false;
|
||||||
|
options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight);
|
||||||
|
Bitmap unscaledBitmap = BitmapFactory.decodeFile(imagePath, options);
|
||||||
|
if (unscaledBitmap == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Bitmap.createScaledBitmap(unscaledBitmap, widthHeight[0], widthHeight[1], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maintain the aspect ratio so the resulting image does not look smooshed
|
||||||
|
*
|
||||||
|
* @param origWidth
|
||||||
|
* @param origHeight
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int[] calculateAspectRatio(int origWidth, int origHeight) {
|
||||||
|
int newWidth = this.targetWidth;
|
||||||
|
int newHeight = this.targetHeight;
|
||||||
|
|
||||||
|
// If no new width or height were specified return the original bitmap
|
||||||
|
if (newWidth <= 0 && newHeight <= 0) {
|
||||||
|
newWidth = origWidth;
|
||||||
|
newHeight = origHeight;
|
||||||
|
}
|
||||||
|
// Only the width was specified
|
||||||
|
else if (newWidth > 0 && newHeight <= 0) {
|
||||||
|
newHeight = (newWidth * origHeight) / origWidth;
|
||||||
|
}
|
||||||
|
// only the height was specified
|
||||||
|
else if (newWidth <= 0 && newHeight > 0) {
|
||||||
|
newWidth = (newHeight * origWidth) / origHeight;
|
||||||
|
}
|
||||||
|
// If the user specified both a positive width and height
|
||||||
|
// (potentially different aspect ratio) then the width or height is
|
||||||
|
// scaled so that the image fits while maintaining aspect ratio.
|
||||||
|
// Alternatively, the specified width and height could have been
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
if (origRatio > newRatio) {
|
||||||
|
newHeight = (newWidth * origHeight) / origWidth;
|
||||||
|
} else if (origRatio < newRatio) {
|
||||||
|
newWidth = (newHeight * origWidth) / origHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] retval = new int[2];
|
||||||
|
retval[0] = newWidth;
|
||||||
|
retval[1] = newHeight;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Figure out what ratio we can load our image into memory at while still being bigger than
|
||||||
|
* our desired width and height
|
||||||
|
*
|
||||||
|
* @param srcWidth
|
||||||
|
* @param srcHeight
|
||||||
|
* @param dstWidth
|
||||||
|
* @param dstHeight
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static int calculateSampleSize(int srcWidth, int srcHeight, int dstWidth, int dstHeight) {
|
||||||
|
final float srcAspect = (float)srcWidth / (float)srcHeight;
|
||||||
|
final float dstAspect = (float)dstWidth / (float)dstHeight;
|
||||||
|
|
||||||
|
if (srcAspect > dstAspect) {
|
||||||
|
return srcWidth / dstWidth;
|
||||||
|
} else {
|
||||||
|
return srcHeight / dstHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a cursor that can be used to determine how many images we have.
|
* Creates a cursor that can be used to determine how many images we have.
|
||||||
*
|
*
|
||||||
* @return a cursor
|
* @return a cursor
|
||||||
*/
|
*/
|
||||||
private Cursor queryImgDB() {
|
private Cursor queryImgDB(Uri contentStore) {
|
||||||
return this.ctx.getContentResolver().query(
|
return this.cordova.getActivity().getContentResolver().query(
|
||||||
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
contentStore,
|
||||||
new String[] { MediaStore.Images.Media._ID },
|
new String[] { MediaStore.Images.Media._ID },
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up after picture taking. Checking for duplicates and that kind of stuff.
|
||||||
|
* @param newImage
|
||||||
|
*/
|
||||||
|
private void cleanup(int imageType, Uri oldImage, Uri newImage, Bitmap bitmap) {
|
||||||
|
if (bitmap != null) {
|
||||||
|
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
|
||||||
|
if (this.saveToPhotoAlbum && newImage != null) {
|
||||||
|
this.scanForGallery(newImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to find out if we are in a situation where the Camera Intent adds to images
|
* 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
|
||||||
@@ -476,19 +697,35 @@ public class CameraLauncher extends Plugin {
|
|||||||
*/
|
*/
|
||||||
private void checkForDuplicateImage(int type) {
|
private void checkForDuplicateImage(int type) {
|
||||||
int diff = 1;
|
int diff = 1;
|
||||||
Cursor cursor = queryImgDB();
|
Uri contentStore = whichContentStore();
|
||||||
|
Cursor cursor = queryImgDB(contentStore);
|
||||||
int currentNumOfImages = cursor.getCount();
|
int currentNumOfImages = cursor.getCount();
|
||||||
|
|
||||||
if (type == FILE_URI) {
|
if (type == FILE_URI && this.saveToPhotoAlbum) {
|
||||||
diff = 2;
|
diff = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete the duplicate file if the difference is 2 for file URI or 1 for Data URL
|
// delete the duplicate file if the difference is 2 for file URI or 1 for Data URL
|
||||||
if ((currentNumOfImages - numPics) == diff) {
|
if ((currentNumOfImages - numPics) == diff) {
|
||||||
cursor.moveToLast();
|
cursor.moveToLast();
|
||||||
int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID))) - 1;
|
int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID)));
|
||||||
Uri uri = Uri.parse(MediaStore.Images.Media.EXTERNAL_CONTENT_URI + "/" + id);
|
if (diff == 2) {
|
||||||
this.ctx.getContentResolver().delete(uri, null, null);
|
id--;
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,16 +738,15 @@ public class CameraLauncher extends Plugin {
|
|||||||
ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream();
|
ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream();
|
||||||
try {
|
try {
|
||||||
if (bitmap.compress(CompressFormat.JPEG, mQuality, jpeg_data)) {
|
if (bitmap.compress(CompressFormat.JPEG, mQuality, jpeg_data)) {
|
||||||
byte[] code = jpeg_data.toByteArray();
|
byte[] code = jpeg_data.toByteArray();
|
||||||
byte[] output = Base64.encodeBase64(code);
|
byte[] output = Base64.encodeBase64(code);
|
||||||
String js_out = new String(output);
|
String js_out = new String(output);
|
||||||
this.success(new PluginResult(PluginResult.Status.OK, js_out), this.callbackId);
|
this.callbackContext.success(js_out);
|
||||||
js_out = null;
|
js_out = null;
|
||||||
output = null;
|
output = null;
|
||||||
code = null;
|
code = null;
|
||||||
}
|
}
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch(Exception e) {
|
|
||||||
this.failPicture("Error compressing image.");
|
this.failPicture("Error compressing image.");
|
||||||
}
|
}
|
||||||
jpeg_data = null;
|
jpeg_data = null;
|
||||||
@@ -522,6 +758,28 @@ public class CameraLauncher extends Plugin {
|
|||||||
* @param err
|
* @param err
|
||||||
*/
|
*/
|
||||||
public void failPicture(String err) {
|
public void failPicture(String err) {
|
||||||
this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
|
this.callbackContext.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scanForGallery(Uri newImage) {
|
||||||
|
this.scanMe = newImage;
|
||||||
|
if(this.conn != null) {
|
||||||
|
this.conn.disconnect();
|
||||||
|
}
|
||||||
|
this.conn = new MediaScannerConnection(this.cordova.getActivity().getApplicationContext(), this);
|
||||||
|
conn.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onMediaScannerConnected() {
|
||||||
|
try{
|
||||||
|
this.conn.scanFile(this.scanMe.toString(), "image/*");
|
||||||
|
} catch (java.lang.IllegalStateException e){
|
||||||
|
LOG.e(LOG_TAG, "Can't scan file in MediaScanner after taking picture");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onScanCompleted(String path, Uri uri) {
|
||||||
|
this.conn.disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,11 +19,13 @@
|
|||||||
package org.apache.cordova;
|
package org.apache.cordova;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import org.apache.cordova.api.CallbackContext;
|
||||||
|
import org.apache.cordova.api.CordovaPlugin;
|
||||||
import org.apache.cordova.api.LOG;
|
import org.apache.cordova.api.LOG;
|
||||||
import org.apache.cordova.api.Plugin;
|
|
||||||
import org.apache.cordova.api.PluginResult;
|
import org.apache.cordova.api.PluginResult;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
@@ -32,17 +34,18 @@ import org.json.JSONObject;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.database.Cursor;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.provider.MediaStore;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class Capture extends CordovaPlugin {
|
||||||
public class Capture extends Plugin {
|
|
||||||
|
|
||||||
private static final String VIDEO_3GPP = "video/3gpp";
|
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 AUDIO_3GPP = "audio/3gpp";
|
||||||
private static final String IMAGE_JPEG = "image/jpeg";
|
private static final String IMAGE_JPEG = "image/jpeg";
|
||||||
|
|
||||||
@@ -52,20 +55,29 @@ public class Capture extends Plugin {
|
|||||||
private static final String LOG_TAG = "Capture";
|
private static final String LOG_TAG = "Capture";
|
||||||
|
|
||||||
private static final int CAPTURE_INTERNAL_ERR = 0;
|
private static final int CAPTURE_INTERNAL_ERR = 0;
|
||||||
private static final int CAPTURE_APPLICATION_BUSY = 1;
|
// private static final int CAPTURE_APPLICATION_BUSY = 1;
|
||||||
private static final int CAPTURE_INVALID_ARGUMENT = 2;
|
// private static final int CAPTURE_INVALID_ARGUMENT = 2;
|
||||||
private static final int CAPTURE_NO_MEDIA_FILES = 3;
|
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 CallbackContext callbackContext; // The callback context from which we were invoked.
|
||||||
private long limit; // the number of pics/vids/clips to take
|
private long limit; // the number of pics/vids/clips to take
|
||||||
private double duration; // optional duration parameter for video recording
|
private double duration; // optional duration parameter for video recording
|
||||||
private JSONArray results; // The array of results to be returned to the user
|
private JSONArray results; // The array of results to be returned to the user
|
||||||
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
|
@Override
|
||||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||||
this.callbackId = callbackId;
|
this.callbackContext = callbackContext;
|
||||||
this.limit = 1;
|
this.limit = 1;
|
||||||
this.duration = 0.0f;
|
this.duration = 0.0f;
|
||||||
this.results = new JSONArray();
|
this.results = new JSONArray();
|
||||||
@@ -77,12 +89,9 @@ public class Capture extends Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action.equals("getFormatData")) {
|
if (action.equals("getFormatData")) {
|
||||||
try {
|
JSONObject obj = getFormatData(args.getString(0), args.getString(1));
|
||||||
JSONObject obj = getFormatData(args.getString(0), args.getString(1));
|
callbackContext.success(obj);
|
||||||
return new PluginResult(PluginResult.Status.OK, obj);
|
return true;
|
||||||
} catch (JSONException e) {
|
|
||||||
return new PluginResult(PluginResult.Status.ERROR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (action.equals("captureAudio")) {
|
else if (action.equals("captureAudio")) {
|
||||||
this.captureAudio();
|
this.captureAudio();
|
||||||
@@ -93,10 +102,11 @@ public class Capture extends Plugin {
|
|||||||
else if (action.equals("captureVideo")) {
|
else if (action.equals("captureVideo")) {
|
||||||
this.captureVideo(duration);
|
this.captureVideo(duration);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
|
return true;
|
||||||
r.setKeepCallback(true);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,35 +116,30 @@ public class Capture extends Plugin {
|
|||||||
* @param mimeType of the file
|
* @param mimeType of the file
|
||||||
* @return a MediaFileData object
|
* @return a MediaFileData object
|
||||||
*/
|
*/
|
||||||
private JSONObject getFormatData(String filePath, String mimeType) {
|
private JSONObject getFormatData(String filePath, String mimeType) throws JSONException {
|
||||||
JSONObject obj = new JSONObject();
|
JSONObject obj = new JSONObject();
|
||||||
try {
|
// setup defaults
|
||||||
// setup defaults
|
obj.put("height", 0);
|
||||||
obj.put("height", 0);
|
obj.put("width", 0);
|
||||||
obj.put("width", 0);
|
obj.put("bitrate", 0);
|
||||||
obj.put("bitrate", 0);
|
obj.put("duration", 0);
|
||||||
obj.put("duration", 0);
|
obj.put("codecs", "");
|
||||||
obj.put("codecs", "");
|
|
||||||
|
|
||||||
// If the mimeType isn't set the rest will fail
|
// If the mimeType isn't set the rest will fail
|
||||||
// so let's see if we can determine it.
|
// so let's see if we can determine it.
|
||||||
if (mimeType == null || mimeType.equals("")) {
|
if (mimeType == null || mimeType.equals("") || "null".equals(mimeType)) {
|
||||||
mimeType = FileUtils.getMimeType(filePath);
|
mimeType = FileUtils.getMimeType(filePath);
|
||||||
}
|
|
||||||
Log.d(LOG_TAG, "Mime type = " + mimeType);
|
|
||||||
|
|
||||||
if (mimeType.equals(IMAGE_JPEG) || filePath.endsWith(".jpg")) {
|
|
||||||
obj = getImageData(filePath, obj);
|
|
||||||
}
|
|
||||||
else if (mimeType.endsWith(AUDIO_3GPP)) {
|
|
||||||
obj = getAudioVideoData(filePath, obj, false);
|
|
||||||
}
|
|
||||||
else if (mimeType.equals(VIDEO_3GPP) || mimeType.equals(VIDEO_MP4)) {
|
|
||||||
obj = getAudioVideoData(filePath, obj, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (JSONException e) {
|
Log.d(LOG_TAG, "Mime type = " + mimeType);
|
||||||
Log.d(LOG_TAG, "Error: setting media file data object");
|
|
||||||
|
if (mimeType.equals(IMAGE_JPEG) || filePath.endsWith(".jpg")) {
|
||||||
|
obj = getImageData(filePath, obj);
|
||||||
|
}
|
||||||
|
else if (mimeType.endsWith(AUDIO_3GPP)) {
|
||||||
|
obj = getAudioVideoData(filePath, obj, false);
|
||||||
|
}
|
||||||
|
else if (mimeType.equals(VIDEO_3GPP) || mimeType.equals(VIDEO_MP4)) {
|
||||||
|
obj = getAudioVideoData(filePath, obj, true);
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@@ -148,10 +153,11 @@ public class Capture extends Plugin {
|
|||||||
* @throws JSONException
|
* @throws JSONException
|
||||||
*/
|
*/
|
||||||
private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException {
|
private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException {
|
||||||
Bitmap bitmap = BitmapFactory.decodeFile(FileUtils.stripFileProtocol(filePath));
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
obj.put("height", bitmap.getHeight());
|
options.inJustDecodeBounds = true;
|
||||||
obj.put("width", bitmap.getWidth());
|
BitmapFactory.decodeFile(FileUtils.stripFileProtocol(filePath), options);
|
||||||
bitmap.recycle();
|
obj.put("height", options.outHeight);
|
||||||
|
obj.put("width", options.outWidth);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,13 +175,12 @@ public class Capture extends Plugin {
|
|||||||
try {
|
try {
|
||||||
player.setDataSource(filePath);
|
player.setDataSource(filePath);
|
||||||
player.prepare();
|
player.prepare();
|
||||||
obj.put("duration", player.getDuration()/1000);
|
obj.put("duration", player.getDuration() / 1000);
|
||||||
if (video) {
|
if (video) {
|
||||||
obj.put("height", player.getVideoHeight());
|
obj.put("height", player.getVideoHeight());
|
||||||
obj.put("width", player.getVideoWidth());
|
obj.put("width", player.getVideoWidth());
|
||||||
}
|
}
|
||||||
}
|
} catch (IOException e) {
|
||||||
catch (IOException e) {
|
|
||||||
Log.d(LOG_TAG, "Error: loading video file");
|
Log.d(LOG_TAG, "Error: loading video file");
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
@@ -187,21 +192,23 @@ public class Capture extends Plugin {
|
|||||||
private void captureAudio() {
|
private void captureAudio() {
|
||||||
Intent intent = new Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION);
|
Intent intent = new Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION);
|
||||||
|
|
||||||
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_AUDIO);
|
this.cordova.startActivityForResult((CordovaPlugin) this, intent, CAPTURE_AUDIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up an intent to capture images. Result handled by onActivityResult()
|
* Sets up an intent to capture images. Result handled by onActivityResult()
|
||||||
*/
|
*/
|
||||||
private void captureImage() {
|
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);
|
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
|
||||||
|
|
||||||
// Specify file so that large image is captured and returned
|
// 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));
|
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((CordovaPlugin) this, intent, CAPTURE_IMAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -212,7 +219,7 @@ public class Capture extends Plugin {
|
|||||||
// Introduced in API 8
|
// Introduced in API 8
|
||||||
//intent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT, duration);
|
//intent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT, duration);
|
||||||
|
|
||||||
this.ctx.startActivityForResult((Plugin) this, intent, CAPTURE_VIDEO);
|
this.cordova.startActivityForResult((CordovaPlugin) this, intent, CAPTURE_VIDEO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -237,7 +244,7 @@ public class Capture extends Plugin {
|
|||||||
|
|
||||||
if (results.length() >= limit) {
|
if (results.length() >= limit) {
|
||||||
// Send Uri back to JavaScript for listening to audio
|
// Send Uri back to JavaScript for listening to audio
|
||||||
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
|
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
|
||||||
} else {
|
} else {
|
||||||
// still need to capture more audio clips
|
// still need to capture more audio clips
|
||||||
captureAudio();
|
captureAudio();
|
||||||
@@ -248,51 +255,42 @@ public class Capture extends Plugin {
|
|||||||
// It crashes in the emulator and on my phone with a null pointer exception
|
// 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
|
// To work around it I had to grab the code from CameraLauncher.java
|
||||||
try {
|
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
|
// Create entry in media store for image
|
||||||
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
|
// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, IMAGE_JPEG);
|
values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, IMAGE_JPEG);
|
||||||
Uri uri = null;
|
Uri uri = null;
|
||||||
try {
|
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) {
|
} catch (UnsupportedOperationException e) {
|
||||||
LOG.d(LOG_TAG, "Can't write to external media storage.");
|
LOG.d(LOG_TAG, "Can't write to external media storage.");
|
||||||
try {
|
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) {
|
} 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."));
|
this.fail(createErrorObject(CAPTURE_INTERNAL_ERR, "Error capturing image - no media storage found."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
FileInputStream fis = new FileInputStream(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/Capture.jpg");
|
||||||
// Add compressed version of captured image to returned media store Uri
|
OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
|
||||||
OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
|
byte[] buffer = new byte[4096];
|
||||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
|
int len;
|
||||||
|
while ((len = fis.read(buffer)) != -1) {
|
||||||
|
os.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
os.flush();
|
||||||
os.close();
|
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
|
// Add image to results
|
||||||
results.put(createMediaFile(uri));
|
results.put(createMediaFile(uri));
|
||||||
|
|
||||||
|
checkForDuplicateImage();
|
||||||
|
|
||||||
if (results.length() >= limit) {
|
if (results.length() >= limit) {
|
||||||
// Send Uri back to JavaScript for viewing image
|
// Send Uri back to JavaScript for viewing image
|
||||||
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
|
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
|
||||||
} else {
|
} else {
|
||||||
// still need to capture more images
|
// still need to capture more images
|
||||||
captureImage();
|
captureImage();
|
||||||
@@ -309,7 +307,7 @@ public class Capture extends Plugin {
|
|||||||
|
|
||||||
if (results.length() >= limit) {
|
if (results.length() >= limit) {
|
||||||
// Send Uri back to JavaScript for viewing video
|
// Send Uri back to JavaScript for viewing video
|
||||||
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
|
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
|
||||||
} else {
|
} else {
|
||||||
// still need to capture more video clips
|
// still need to capture more video clips
|
||||||
captureVideo(duration);
|
captureVideo(duration);
|
||||||
@@ -320,7 +318,7 @@ public class Capture extends Plugin {
|
|||||||
else if (resultCode == Activity.RESULT_CANCELED) {
|
else if (resultCode == Activity.RESULT_CANCELED) {
|
||||||
// If we have partial results send them back to the user
|
// If we have partial results send them back to the user
|
||||||
if (results.length() > 0) {
|
if (results.length() > 0) {
|
||||||
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
|
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
|
||||||
}
|
}
|
||||||
// user canceled the action
|
// user canceled the action
|
||||||
else {
|
else {
|
||||||
@@ -331,7 +329,7 @@ public class Capture extends Plugin {
|
|||||||
else {
|
else {
|
||||||
// If we have partial results send them back to the user
|
// If we have partial results send them back to the user
|
||||||
if (results.length() > 0) {
|
if (results.length() > 0) {
|
||||||
this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId);
|
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
|
||||||
}
|
}
|
||||||
// something bad happened
|
// something bad happened
|
||||||
else {
|
else {
|
||||||
@@ -347,15 +345,14 @@ public class Capture extends Plugin {
|
|||||||
* @return a JSONObject that represents a File
|
* @return a JSONObject that represents a File
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private JSONObject createMediaFile(Uri data){
|
private JSONObject createMediaFile(Uri data) {
|
||||||
File fp = new File(FileUtils.getRealPathFromURI(data, this.ctx));
|
File fp = new File(FileUtils.getRealPathFromURI(data, this.cordova));
|
||||||
JSONObject obj = new JSONObject();
|
JSONObject obj = new JSONObject();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// File properties
|
// File properties
|
||||||
obj.put("name", fp.getName());
|
obj.put("name", fp.getName());
|
||||||
obj.put("fullPath", "file://" + fp.getAbsolutePath());
|
obj.put("fullPath", "file://" + fp.getAbsolutePath());
|
||||||
|
|
||||||
// Because of an issue with MimeTypeMap.getMimeTypeFromExtension() all .3gpp files
|
// 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
|
// 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.
|
// is stored in the audio or video content store.
|
||||||
@@ -396,6 +393,51 @@ public class Capture extends Plugin {
|
|||||||
* @param err
|
* @param err
|
||||||
*/
|
*/
|
||||||
public void fail(JSONObject err) {
|
public void fail(JSONObject err) {
|
||||||
this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId);
|
this.callbackContext.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,24 +20,27 @@ package org.apache.cordova;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.cordova.api.CallbackContext;
|
||||||
import org.apache.cordova.api.CordovaInterface;
|
import org.apache.cordova.api.CordovaInterface;
|
||||||
import org.apache.cordova.api.Plugin;
|
import org.apache.cordova.api.CordovaPlugin;
|
||||||
import org.apache.cordova.api.PluginResult;
|
import org.apache.cordova.api.PluginResult;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
|
||||||
import android.hardware.Sensor;
|
import android.hardware.Sensor;
|
||||||
import android.hardware.SensorEvent;
|
import android.hardware.SensorEvent;
|
||||||
import android.hardware.SensorEventListener;
|
import android.hardware.SensorEventListener;
|
||||||
import android.hardware.SensorManager;
|
import android.hardware.SensorManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class listens to the compass sensor and stores the latest heading value.
|
* This class listens to the compass sensor and stores the latest heading value.
|
||||||
*/
|
*/
|
||||||
public class CompassListener extends Plugin implements SensorEventListener {
|
public class CompassListener extends CordovaPlugin implements SensorEventListener {
|
||||||
|
|
||||||
public static int STOPPED = 0;
|
public static int STOPPED = 0;
|
||||||
public static int STARTING = 1;
|
public static int STARTING = 1;
|
||||||
@@ -55,6 +58,8 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
|||||||
private SensorManager sensorManager;// Sensor manager
|
private SensorManager sensorManager;// Sensor manager
|
||||||
Sensor mSensor; // Compass sensor returned by sensor manager
|
Sensor mSensor; // Compass sensor returned by sensor manager
|
||||||
|
|
||||||
|
private CallbackContext callbackContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
@@ -68,96 +73,63 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
|||||||
* Sets the context of the Command. This can then be used to do things like
|
* Sets the context of the Command. This can then be used to do things like
|
||||||
* get file paths associated with the Activity.
|
* get file paths associated with the Activity.
|
||||||
*
|
*
|
||||||
* @param ctx The context of the main Activity.
|
* @param cordova The context of the main Activity.
|
||||||
|
* @param webView The CordovaWebView Cordova is running in.
|
||||||
*/
|
*/
|
||||||
public void setContext(CordovaInterface ctx) {
|
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
|
||||||
super.setContext(ctx);
|
super.initialize(cordova, webView);
|
||||||
this.sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
|
this.sensorManager = (SensorManager) cordova.getActivity().getSystemService(Context.SENSOR_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the request and returns PluginResult.
|
* Executes the request and returns PluginResult.
|
||||||
*
|
*
|
||||||
* @param action The action to execute.
|
* @param action The action to execute.
|
||||||
* @param args JSONArry of arguments for the plugin.
|
* @param args JSONArry of arguments for the plugin.
|
||||||
* @param callbackId The callback id used when calling back into JavaScript.
|
* @param callbackS=Context The callback id used when calling back into JavaScript.
|
||||||
* @return A PluginResult object with a status and message.
|
* @return True if the action was valid.
|
||||||
|
* @throws JSONException
|
||||||
*/
|
*/
|
||||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||||
PluginResult.Status status = PluginResult.Status.OK;
|
if (action.equals("start")) {
|
||||||
String result = "";
|
this.start();
|
||||||
|
|
||||||
try {
|
|
||||||
if (action.equals("start")) {
|
|
||||||
this.start();
|
|
||||||
}
|
|
||||||
else if (action.equals("stop")) {
|
|
||||||
this.stop();
|
|
||||||
}
|
|
||||||
else if (action.equals("getStatus")) {
|
|
||||||
int i = this.getStatus();
|
|
||||||
return new PluginResult(status, i);
|
|
||||||
}
|
|
||||||
else if (action.equals("getHeading")) {
|
|
||||||
// If not running, then this is an async call, so don't worry about waiting
|
|
||||||
if (this.status != CompassListener.RUNNING) {
|
|
||||||
int r = this.start();
|
|
||||||
if (r == CompassListener.ERROR_FAILED_TO_START) {
|
|
||||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, CompassListener.ERROR_FAILED_TO_START);
|
|
||||||
}
|
|
||||||
// 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) {
|
|
||||||
return new PluginResult(PluginResult.Status.IO_EXCEPTION, CompassListener.ERROR_FAILED_TO_START);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new PluginResult(status, getCompassHeading());
|
|
||||||
}
|
|
||||||
else if (action.equals("setTimeout")) {
|
|
||||||
this.setTimeout(args.getLong(0));
|
|
||||||
}
|
|
||||||
else if (action.equals("getTimeout")) {
|
|
||||||
long l = this.getTimeout();
|
|
||||||
return new PluginResult(status, l);
|
|
||||||
} else {
|
|
||||||
// Unsupported action
|
|
||||||
return new PluginResult(PluginResult.Status.INVALID_ACTION);
|
|
||||||
}
|
|
||||||
return new PluginResult(status, result);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
|
||||||
}
|
}
|
||||||
}
|
else if (action.equals("stop")) {
|
||||||
|
this.stop();
|
||||||
/**
|
}
|
||||||
* Identifies if action to be executed returns a value and should be run synchronously.
|
else if (action.equals("getStatus")) {
|
||||||
*
|
int i = this.getStatus();
|
||||||
* @param action The action to execute
|
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, i));
|
||||||
* @return T=returns value
|
|
||||||
*/
|
|
||||||
public boolean isSynch(String action) {
|
|
||||||
if (action.equals("getStatus")) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else if (action.equals("getHeading")) {
|
else if (action.equals("getHeading")) {
|
||||||
// Can only return value if RUNNING
|
// If not running, then this is an async call, so don't worry about waiting
|
||||||
if (this.status == CompassListener.RUNNING) {
|
if (this.status != CompassListener.RUNNING) {
|
||||||
return true;
|
int r = this.start();
|
||||||
|
if (r == CompassListener.ERROR_FAILED_TO_START) {
|
||||||
|
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, CompassListener.ERROR_FAILED_TO_START));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Set a timeout callback on the main thread.
|
||||||
|
Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
handler.postDelayed(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
CompassListener.this.timeout();
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, getCompassHeading()));
|
||||||
|
}
|
||||||
|
else if (action.equals("setTimeout")) {
|
||||||
|
this.setTimeout(args.getLong(0));
|
||||||
}
|
}
|
||||||
else if (action.equals("getTimeout")) {
|
else if (action.equals("getTimeout")) {
|
||||||
return true;
|
long l = this.getTimeout();
|
||||||
|
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, l));
|
||||||
|
} else {
|
||||||
|
// Unsupported action
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -167,6 +139,13 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
|||||||
this.stop();
|
this.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when app has navigated and JS listeners have been destroyed.
|
||||||
|
*/
|
||||||
|
public void onReset() {
|
||||||
|
this.stop();
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
// LOCAL METHODS
|
// LOCAL METHODS
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
@@ -184,6 +163,7 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get compass sensor from sensor manager
|
// Get compass sensor from sensor manager
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
|
List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
|
||||||
|
|
||||||
// If found, then register as listener
|
// If found, then register as listener
|
||||||
@@ -212,11 +192,22 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
|||||||
this.setStatus(CompassListener.STOPPED);
|
this.setStatus(CompassListener.STOPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after a delay to time out if the listener has not attached fast enough.
|
||||||
|
*/
|
||||||
|
private void timeout() {
|
||||||
|
if (this.status == CompassListener.STARTING) {
|
||||||
|
this.setStatus(CompassListener.ERROR_FAILED_TO_START);
|
||||||
|
if (this.callbackContext != null) {
|
||||||
|
this.callbackContext.error("Compass listener failed to start.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sensor listener event.
|
* Sensor listener event.
|
||||||
*
|
*
|
||||||
@@ -288,19 +279,15 @@ public class CompassListener extends Plugin implements SensorEventListener {
|
|||||||
*
|
*
|
||||||
* @return a compass heading
|
* @return a compass heading
|
||||||
*/
|
*/
|
||||||
private JSONObject getCompassHeading() {
|
private JSONObject getCompassHeading() throws JSONException {
|
||||||
JSONObject obj = new JSONObject();
|
JSONObject obj = new JSONObject();
|
||||||
|
|
||||||
try {
|
obj.put("magneticHeading", this.getHeading());
|
||||||
obj.put("magneticHeading", this.getHeading());
|
obj.put("trueHeading", 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
|
||||||
// is defined as the difference between true and magnetic always return zero
|
obj.put("headingAccuracy", 0);
|
||||||
obj.put("headingAccuracy", 0);
|
obj.put("timestamp", this.timeStamp);
|
||||||
obj.put("timestamp", this.timeStamp);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
// Should never happen
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import android.content.Context;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
|
|
||||||
|
import org.apache.cordova.api.CordovaInterface;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@@ -36,7 +37,7 @@ import org.json.JSONObject;
|
|||||||
public abstract class ContactAccessor {
|
public abstract class ContactAccessor {
|
||||||
|
|
||||||
protected final String LOG_TAG = "ContactsAccessor";
|
protected final String LOG_TAG = "ContactsAccessor";
|
||||||
protected Context mApp;
|
protected CordovaInterface mApp;
|
||||||
protected WebView mView;
|
protected WebView mView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,7 +76,7 @@ public abstract class ContactAccessor {
|
|||||||
map.put("urls", true);
|
map.put("urls", true);
|
||||||
map.put("photos", true);
|
map.put("photos", true);
|
||||||
map.put("categories", true);
|
map.put("categories", true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (int i=0; i<fields.length(); i++) {
|
for (int i=0; i<fields.length(); i++) {
|
||||||
key = fields.getString(i);
|
key = fields.getString(i);
|
||||||
@@ -121,7 +122,7 @@ public abstract class ContactAccessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (JSONException e) {
|
catch (JSONException e) {
|
||||||
Log.e(LOG_TAG, e.getMessage(), e);
|
Log.e(LOG_TAG, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
@@ -147,7 +148,7 @@ public abstract class ContactAccessor {
|
|||||||
value = null;
|
value = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (JSONException e) {
|
catch (JSONException e) {
|
||||||
Log.d(LOG_TAG, "Could not get = " + e.getMessage());
|
Log.d(LOG_TAG, "Could not get = " + e.getMessage());
|
||||||
}
|
}
|
||||||
@@ -176,8 +177,8 @@ public abstract class ContactAccessor {
|
|||||||
*/
|
*/
|
||||||
public abstract boolean remove(String id);
|
public abstract boolean remove(String id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that represents the where clause to be used in the database query
|
* A class that represents the where clause to be used in the database query
|
||||||
*/
|
*/
|
||||||
class WhereOptions {
|
class WhereOptions {
|
||||||
private String where;
|
private String where;
|
||||||
|
|||||||
@@ -18,14 +18,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.cordova;
|
package org.apache.cordova;
|
||||||
|
|
||||||
import org.apache.cordova.api.Plugin;
|
import org.apache.cordova.api.CallbackContext;
|
||||||
|
import org.apache.cordova.api.CordovaPlugin;
|
||||||
import org.apache.cordova.api.PluginResult;
|
import org.apache.cordova.api.PluginResult;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class ContactManager extends Plugin {
|
public class ContactManager extends CordovaPlugin {
|
||||||
|
|
||||||
private ContactAccessor contactAccessor;
|
private ContactAccessor contactAccessor;
|
||||||
private static final String LOG_TAG = "Contact Query";
|
private static final String LOG_TAG = "Contact Query";
|
||||||
@@ -47,21 +48,19 @@ public class ContactManager extends Plugin {
|
|||||||
/**
|
/**
|
||||||
* Executes the request and returns PluginResult.
|
* Executes the request and returns PluginResult.
|
||||||
*
|
*
|
||||||
* @param action The action to execute.
|
* @param action The action to execute.
|
||||||
* @param args JSONArry of arguments for the plugin.
|
* @param args JSONArray of arguments for the plugin.
|
||||||
* @param callbackId The callback id used when calling back into JavaScript.
|
* @param callbackContext The callback context used when calling back into JavaScript.
|
||||||
* @return A PluginResult object with a status and message.
|
* @return True if the action was valid, false otherwise.
|
||||||
*/
|
*/
|
||||||
public PluginResult execute(String action, JSONArray args, String callbackId) {
|
public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
||||||
PluginResult.Status status = PluginResult.Status.OK;
|
|
||||||
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.
|
* do not support this as of Cordova 1.0.
|
||||||
*/
|
*/
|
||||||
if (android.os.Build.VERSION.RELEASE.startsWith("1.")) {
|
if (android.os.Build.VERSION.RELEASE.startsWith("1.")) {
|
||||||
return new PluginResult(PluginResult.Status.ERROR, ContactManager.NOT_SUPPORTED_ERROR);
|
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, ContactManager.NOT_SUPPORTED_ERROR));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,33 +68,55 @@ public class ContactManager extends Plugin {
|
|||||||
* older phones.
|
* older phones.
|
||||||
*/
|
*/
|
||||||
if (this.contactAccessor == null) {
|
if (this.contactAccessor == null) {
|
||||||
this.contactAccessor = new ContactAccessorSdk5(this.webView, this.ctx.getContext());
|
this.contactAccessor = new ContactAccessorSdk5(this.webView, this.cordova);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (action.equals("search")) {
|
||||||
if (action.equals("search")) {
|
final JSONArray filter = args.getJSONArray(0);
|
||||||
JSONArray res = contactAccessor.search(args.getJSONArray(0), args.optJSONObject(1));
|
final JSONObject options = args.getJSONObject(1);
|
||||||
return new PluginResult(status, res);
|
this.cordova.getThreadPool().execute(new Runnable() {
|
||||||
}
|
public void run() {
|
||||||
else if (action.equals("save")) {
|
JSONArray res = contactAccessor.search(filter, options);
|
||||||
String id = contactAccessor.save(args.getJSONObject(0));
|
callbackContext.success(res);
|
||||||
if (id != null) {
|
}
|
||||||
JSONObject res = contactAccessor.getContactById(id);
|
});
|
||||||
|
}
|
||||||
|
else if (action.equals("save")) {
|
||||||
|
final JSONObject contact = args.getJSONObject(0);
|
||||||
|
this.cordova.getThreadPool().execute(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
JSONObject res = null;
|
||||||
|
String id = contactAccessor.save(contact);
|
||||||
|
if (id != null) {
|
||||||
|
try {
|
||||||
|
res = contactAccessor.getContactById(id);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(LOG_TAG, "JSON fail.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (res != null) {
|
if (res != null) {
|
||||||
return new PluginResult(status, res);
|
callbackContext.success(res);
|
||||||
|
} else {
|
||||||
|
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, UNKNOWN_ERROR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
else if (action.equals("remove")) {
|
|
||||||
if (contactAccessor.remove(args.getString(0))) {
|
|
||||||
return new PluginResult(status, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If we get to this point an error has occurred
|
|
||||||
return new PluginResult(PluginResult.Status.ERROR, ContactManager.UNKNOWN_ERROR);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
Log.e(LOG_TAG, e.getMessage(), e);
|
|
||||||
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
|
||||||
}
|
}
|
||||||
|
else if (action.equals("remove")) {
|
||||||
|
final String contactId = args.getString(0);
|
||||||
|
this.cordova.getThreadPool().execute(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (contactAccessor.remove(contactId)) {
|
||||||
|
callbackContext.success();
|
||||||
|
} else {
|
||||||
|
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, UNKNOWN_ERROR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,16 +17,19 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
package org.apache.cordova;
|
package org.apache.cordova;
|
||||||
|
|
||||||
|
import org.apache.cordova.api.CordovaInterface;
|
||||||
import org.apache.cordova.api.LOG;
|
import org.apache.cordova.api.LOG;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.view.Gravity;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup.LayoutParams;
|
||||||
import android.webkit.ConsoleMessage;
|
import android.webkit.ConsoleMessage;
|
||||||
import android.webkit.JsPromptResult;
|
import android.webkit.JsPromptResult;
|
||||||
import android.webkit.JsResult;
|
import android.webkit.JsResult;
|
||||||
@@ -35,24 +38,50 @@ import android.webkit.WebStorage;
|
|||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
import android.webkit.GeolocationPermissions.Callback;
|
import android.webkit.GeolocationPermissions.Callback;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is the WebChromeClient that implements callbacks for our web view.
|
* This class is the WebChromeClient that implements callbacks for our web view.
|
||||||
*/
|
*/
|
||||||
public class CordovaChromeClient extends WebChromeClient {
|
public class CordovaChromeClient extends WebChromeClient {
|
||||||
|
|
||||||
|
|
||||||
private String TAG = "CordovaLog";
|
private String TAG = "CordovaLog";
|
||||||
private long MAX_QUOTA = 100 * 1024 * 1024;
|
private long MAX_QUOTA = 100 * 1024 * 1024;
|
||||||
private DroidGap ctx;
|
private CordovaInterface cordova;
|
||||||
|
private CordovaWebView appView;
|
||||||
|
|
||||||
|
// the video progress view
|
||||||
|
private View mVideoProgressView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param ctx
|
* @param cordova
|
||||||
*/
|
*/
|
||||||
public CordovaChromeClient(Context ctx) {
|
public CordovaChromeClient(CordovaInterface cordova) {
|
||||||
this.ctx = (DroidGap) ctx;
|
this.cordova = cordova;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param ctx
|
||||||
|
* @param app
|
||||||
|
*/
|
||||||
|
public CordovaChromeClient(CordovaInterface ctx, CordovaWebView app) {
|
||||||
|
this.cordova = ctx;
|
||||||
|
this.appView = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param view
|
||||||
|
*/
|
||||||
|
public void setWebView(CordovaWebView view) {
|
||||||
|
this.appView = view;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,35 +94,35 @@ public class CordovaChromeClient extends WebChromeClient {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
|
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.setMessage(message);
|
||||||
dlg.setTitle("Alert");
|
dlg.setTitle("Alert");
|
||||||
//Don't let alerts break the back button
|
//Don't let alerts break the back button
|
||||||
dlg.setCancelable(true);
|
dlg.setCancelable(true);
|
||||||
dlg.setPositiveButton(android.R.string.ok,
|
dlg.setPositiveButton(android.R.string.ok,
|
||||||
new AlertDialog.OnClickListener() {
|
new AlertDialog.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
result.confirm();
|
result.confirm();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dlg.setOnCancelListener(
|
dlg.setOnCancelListener(
|
||||||
new DialogInterface.OnCancelListener() {
|
new DialogInterface.OnCancelListener() {
|
||||||
public void onCancel(DialogInterface dialog) {
|
public void onCancel(DialogInterface dialog) {
|
||||||
result.confirm();
|
result.cancel();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
|
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
|
||||||
//DO NOTHING
|
//DO NOTHING
|
||||||
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
||||||
if(keyCode == KeyEvent.KEYCODE_BACK)
|
if (keyCode == KeyEvent.KEYCODE_BACK)
|
||||||
{
|
{
|
||||||
result.confirm();
|
result.confirm();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dlg.create();
|
dlg.create();
|
||||||
dlg.show();
|
dlg.show();
|
||||||
return true;
|
return true;
|
||||||
@@ -109,40 +138,40 @@ public class CordovaChromeClient extends WebChromeClient {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
|
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.setMessage(message);
|
||||||
dlg.setTitle("Confirm");
|
dlg.setTitle("Confirm");
|
||||||
dlg.setCancelable(true);
|
dlg.setCancelable(true);
|
||||||
dlg.setPositiveButton(android.R.string.ok,
|
dlg.setPositiveButton(android.R.string.ok,
|
||||||
new DialogInterface.OnClickListener() {
|
new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
result.confirm();
|
result.confirm();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dlg.setNegativeButton(android.R.string.cancel,
|
dlg.setNegativeButton(android.R.string.cancel,
|
||||||
new DialogInterface.OnClickListener() {
|
new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
result.cancel();
|
result.cancel();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dlg.setOnCancelListener(
|
dlg.setOnCancelListener(
|
||||||
new DialogInterface.OnCancelListener() {
|
new DialogInterface.OnCancelListener() {
|
||||||
public void onCancel(DialogInterface dialog) {
|
public void onCancel(DialogInterface dialog) {
|
||||||
result.cancel();
|
result.cancel();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
|
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
|
||||||
//DO NOTHING
|
//DO NOTHING
|
||||||
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
||||||
if(keyCode == KeyEvent.KEYCODE_BACK)
|
if (keyCode == KeyEvent.KEYCODE_BACK)
|
||||||
{
|
{
|
||||||
result.cancel();
|
result.cancel();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dlg.create();
|
dlg.create();
|
||||||
dlg.show();
|
dlg.show();
|
||||||
return true;
|
return true;
|
||||||
@@ -168,11 +197,11 @@ public class CordovaChromeClient extends WebChromeClient {
|
|||||||
// Security check to make sure any requests are coming from the page initially
|
// Security check to make sure any requests are coming from the page initially
|
||||||
// loaded in webview and not another loaded in an iframe.
|
// loaded in webview and not another loaded in an iframe.
|
||||||
boolean reqOk = false;
|
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;
|
reqOk = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calling PluginManager.exec() to call a native service using
|
// Calling PluginManager.exec() to call a native service using
|
||||||
// prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true]));
|
// prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true]));
|
||||||
if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) {
|
if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) {
|
||||||
JSONArray array;
|
JSONArray array;
|
||||||
@@ -181,73 +210,54 @@ public class CordovaChromeClient extends WebChromeClient {
|
|||||||
String service = array.getString(0);
|
String service = array.getString(0);
|
||||||
String action = array.getString(1);
|
String action = array.getString(1);
|
||||||
String callbackId = array.getString(2);
|
String callbackId = array.getString(2);
|
||||||
boolean async = array.getBoolean(3);
|
String r = this.appView.exposedJsApi.exec(service, action, callbackId, message);
|
||||||
String r = ctx.pluginManager.exec(service, action, callbackId, message, async);
|
result.confirm(r == null ? "" : r);
|
||||||
result.confirm(r);
|
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Polling for JavaScript messages
|
// Sets the native->JS bridge mode.
|
||||||
|
else if (reqOk && defaultValue != null && defaultValue.equals("gap_bridge_mode:")) {
|
||||||
|
this.appView.exposedJsApi.setNativeToJsBridgeMode(Integer.parseInt(message));
|
||||||
|
result.confirm("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polling for JavaScript messages
|
||||||
else if (reqOk && defaultValue != null && defaultValue.equals("gap_poll:")) {
|
else if (reqOk && defaultValue != null && defaultValue.equals("gap_poll:")) {
|
||||||
String r = ctx.callbackServer.getJavascript();
|
String r = this.appView.exposedJsApi.retrieveJsMessages();
|
||||||
result.confirm(r);
|
result.confirm(r == null ? "" : r);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calling into CallbackServer
|
// Do NO-OP so older code doesn't display dialog
|
||||||
else if (reqOk && defaultValue != null && defaultValue.equals("gap_callbackServer:")) {
|
else if (defaultValue != null && defaultValue.equals("gap_init:")) {
|
||||||
String r = "";
|
|
||||||
if (message.equals("usePolling")) {
|
|
||||||
r = ""+ ctx.callbackServer.usePolling();
|
|
||||||
}
|
|
||||||
else if (message.equals("restartServer")) {
|
|
||||||
ctx.callbackServer.restartServer();
|
|
||||||
}
|
|
||||||
else if (message.equals("getPort")) {
|
|
||||||
r = Integer.toString(ctx.callbackServer.getPort());
|
|
||||||
}
|
|
||||||
else if (message.equals("getToken")) {
|
|
||||||
r = ctx.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");
|
result.confirm("OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show dialog
|
// Show dialog
|
||||||
else {
|
else {
|
||||||
final JsPromptResult res = result;
|
final JsPromptResult res = result;
|
||||||
AlertDialog.Builder dlg = new AlertDialog.Builder(this.ctx);
|
AlertDialog.Builder dlg = new AlertDialog.Builder(this.cordova.getActivity());
|
||||||
dlg.setMessage(message);
|
dlg.setMessage(message);
|
||||||
final EditText input = new EditText(this.ctx);
|
final EditText input = new EditText(this.cordova.getActivity());
|
||||||
if (defaultValue != null) {
|
if (defaultValue != null) {
|
||||||
input.setText(defaultValue);
|
input.setText(defaultValue);
|
||||||
}
|
}
|
||||||
dlg.setView(input);
|
dlg.setView(input);
|
||||||
dlg.setCancelable(false);
|
dlg.setCancelable(false);
|
||||||
dlg.setPositiveButton(android.R.string.ok,
|
dlg.setPositiveButton(android.R.string.ok,
|
||||||
new DialogInterface.OnClickListener() {
|
new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
String usertext = input.getText().toString();
|
String usertext = input.getText().toString();
|
||||||
res.confirm(usertext);
|
res.confirm(usertext);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dlg.setNegativeButton(android.R.string.cancel,
|
dlg.setNegativeButton(android.R.string.cancel,
|
||||||
new DialogInterface.OnClickListener() {
|
new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
res.cancel();
|
res.cancel();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dlg.create();
|
dlg.create();
|
||||||
dlg.show();
|
dlg.show();
|
||||||
}
|
}
|
||||||
@@ -270,7 +280,7 @@ public class CordovaChromeClient extends WebChromeClient {
|
|||||||
{
|
{
|
||||||
LOG.d(TAG, "DroidGap: onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
|
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
|
//increase for 1Mb
|
||||||
long newQuota = estimatedSize;
|
long newQuota = estimatedSize;
|
||||||
@@ -286,17 +296,24 @@ public class CordovaChromeClient extends WebChromeClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html
|
// console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html
|
||||||
|
// Expect this to not compile in a future Android release!
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public void onConsoleMessage(String message, int lineNumber, String sourceID)
|
public void onConsoleMessage(String message, int lineNumber, String sourceID)
|
||||||
{
|
{
|
||||||
LOG.d(TAG, "%s: Line %d : %s", sourceID, lineNumber, message);
|
//This is only for Android 2.1
|
||||||
super.onConsoleMessage(message, lineNumber, sourceID);
|
if(android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.ECLAIR_MR1)
|
||||||
|
{
|
||||||
|
LOG.d(TAG, "%s: Line %d : %s", sourceID, lineNumber, message);
|
||||||
|
super.onConsoleMessage(message, lineNumber, sourceID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TargetApi(8)
|
||||||
@Override
|
@Override
|
||||||
public boolean onConsoleMessage(ConsoleMessage consoleMessage)
|
public boolean onConsoleMessage(ConsoleMessage consoleMessage)
|
||||||
{
|
{
|
||||||
if(consoleMessage.message() != null)
|
if (consoleMessage.message() != null)
|
||||||
LOG.d(TAG, consoleMessage.message());
|
LOG.d(TAG, consoleMessage.message());
|
||||||
return super.onConsoleMessage(consoleMessage);
|
return super.onConsoleMessage(consoleMessage);
|
||||||
}
|
}
|
||||||
@@ -312,6 +329,45 @@ public class CordovaChromeClient extends WebChromeClient {
|
|||||||
super.onGeolocationPermissionsShowPrompt(origin, callback);
|
super.onGeolocationPermissionsShowPrompt(origin, callback);
|
||||||
callback.invoke(origin, true, false);
|
callback.invoke(origin, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// API level 7 is required for this, see if we could lower this using something else
|
||||||
|
@Override
|
||||||
|
public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) {
|
||||||
|
this.appView.showCustomView(view, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHideCustomView() {
|
||||||
|
this.appView.hideCustomView();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
/**
|
||||||
|
* Ask the host application for a custom progress view to show while
|
||||||
|
* a <video> is loading.
|
||||||
|
* @return View The progress view.
|
||||||
|
*/
|
||||||
|
public View getVideoLoadingProgressView() {
|
||||||
|
|
||||||
|
if (mVideoProgressView == null) {
|
||||||
|
// Create a new Loading view programmatically.
|
||||||
|
|
||||||
|
// create the linear layout
|
||||||
|
LinearLayout layout = new LinearLayout(this.appView.getContext());
|
||||||
|
layout.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||||
|
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
|
||||||
|
layout.setLayoutParams(layoutParams);
|
||||||
|
// the proress bar
|
||||||
|
ProgressBar bar = new ProgressBar(this.appView.getContext());
|
||||||
|
LinearLayout.LayoutParams barLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||||
|
barLayoutParams.gravity = Gravity.CENTER;
|
||||||
|
bar.setLayoutParams(barLayoutParams);
|
||||||
|
layout.addView(bar);
|
||||||
|
|
||||||
|
mVideoProgressView = layout;
|
||||||
|
}
|
||||||
|
return mVideoProgressView;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
import org.apache.cordova.api.CallbackContext;
|
||||||
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.location.LocationListener;
|
import android.location.LocationListener;
|
||||||
@@ -39,8 +40,8 @@ public class CordovaLocationListener implements LocationListener {
|
|||||||
private GeoBroker owner;
|
private GeoBroker owner;
|
||||||
protected boolean running = false;
|
protected boolean running = false;
|
||||||
|
|
||||||
public HashMap<String, String> watches = new HashMap<String, String>();
|
public HashMap<String, CallbackContext> watches = new HashMap<String, CallbackContext>();
|
||||||
private List<String> callbacks = new ArrayList<String>();
|
private List<CallbackContext> callbacks = new ArrayList<CallbackContext>();
|
||||||
|
|
||||||
private String TAG = "[Cordova Location Listener]";
|
private String TAG = "[Cordova Location Listener]";
|
||||||
|
|
||||||
@@ -51,30 +52,38 @@ public class CordovaLocationListener implements LocationListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void fail(int code, String message) {
|
protected void fail(int code, String message) {
|
||||||
for (String callbackId: this.callbacks)
|
for (CallbackContext callbackContext: this.callbacks)
|
||||||
{
|
{
|
||||||
this.owner.fail(code, message, callbackId);
|
this.owner.fail(code, message, callbackContext);
|
||||||
|
}
|
||||||
|
if(this.owner.isGlobalListener(this))
|
||||||
|
{
|
||||||
|
Log.d(TAG, "Stopping global listener");
|
||||||
|
this.stop();
|
||||||
}
|
}
|
||||||
this.callbacks.clear();
|
this.callbacks.clear();
|
||||||
|
|
||||||
Iterator it = this.watches.entrySet().iterator();
|
Iterator<CallbackContext> it = this.watches.values().iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Map.Entry pairs = (Map.Entry)it.next();
|
this.owner.fail(code, message, it.next());
|
||||||
this.owner.fail(code, message, (String)pairs.getValue());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void win(Location loc) {
|
private void win(Location loc) {
|
||||||
for (String callbackId: this.callbacks)
|
for (CallbackContext callbackContext: this.callbacks)
|
||||||
{
|
{
|
||||||
this.owner.win(loc, callbackId);
|
this.owner.win(loc, callbackContext);
|
||||||
|
}
|
||||||
|
if(this.owner.isGlobalListener(this))
|
||||||
|
{
|
||||||
|
Log.d(TAG, "Stopping global listener");
|
||||||
|
this.stop();
|
||||||
}
|
}
|
||||||
this.callbacks.clear();
|
this.callbacks.clear();
|
||||||
|
|
||||||
Iterator it = this.watches.entrySet().iterator();
|
Iterator<CallbackContext> it = this.watches.values().iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Map.Entry pairs = (Map.Entry)it.next();
|
this.owner.win(loc, it.next());
|
||||||
this.owner.win(loc, (String)pairs.getValue());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,14 +149,14 @@ public class CordovaLocationListener implements LocationListener {
|
|||||||
return this.watches.size() + this.callbacks.size();
|
return this.watches.size() + this.callbacks.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addWatch(String timerId, String callbackId) {
|
public void addWatch(String timerId, CallbackContext callbackContext) {
|
||||||
this.watches.put(timerId, callbackId);
|
this.watches.put(timerId, callbackContext);
|
||||||
if (this.size() == 1) {
|
if (this.size() == 1) {
|
||||||
this.start();
|
this.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void addCallback(String callbackId) {
|
public void addCallback(CallbackContext callbackContext) {
|
||||||
this.callbacks.add(callbackId);
|
this.callbacks.add(callbackContext);
|
||||||
if (this.size() == 1) {
|
if (this.size() == 1) {
|
||||||
this.start();
|
this.start();
|
||||||
}
|
}
|
||||||
|
|||||||