mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-09-30 16:52:21 +02:00
Compare commits
805 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c7da9a45ee | |||
| aa733fbfb1 | |||
| d2b8f65612 | |||
| cf6ac06f73 | |||
| 496ad9c4e2 | |||
| 657ec17559 | |||
| 62c9af5cba | |||
| a4f16a1f30 | |||
| 1b595ee7fe | |||
| fa556e4e33 | |||
| 391d718909 | |||
| 2ce14e443d | |||
| cdf0a3a3e7 | |||
| f00f9a5277 | |||
| 7112642e89 | |||
| 3714c21f97 | |||
| 24c49b7f2f | |||
| b16429f3f8 | |||
| 27734495f4 | |||
| 097b338d19 | |||
| cbb8450435 | |||
| 3b7e0a91bd | |||
| d9a1e56282 | |||
| b63e74369c | |||
| 4d0ba06cba | |||
| c4369dc237 | |||
| 99dd212496 | |||
| 6e41033ed6 | |||
| 90a5cb7aae | |||
| bccfbaa03b | |||
| e32ff7116d | |||
| 00214843cb | |||
| dd4054c4fc | |||
| 0b40b92340 | |||
| 60a3c41003 | |||
| f501c60de1 | |||
| b985a935b0 | |||
| a2f1790db2 | |||
| 5784ab63cc | |||
| fd857c2586 | |||
| 29df8762e2 | |||
| 32e13c3495 | |||
| e6151b3b71 | |||
| 6823b08651 | |||
| b588bb02f4 | |||
| faf7b6efa2 | |||
| 03492da2cd | |||
| 8abfc2ada0 | |||
| a262a2ef71 | |||
| 435a38f1d1 | |||
| 91d7db7c01 | |||
| e298c88728 | |||
| d58e7a58d0 | |||
| e530412ef0 | |||
| 1d5e2dc4d5 | |||
| d0b5faf266 | |||
| 76e8a39276 | |||
| 66fe8e694f | |||
| abd8a230b4 | |||
| 565662a8aa | |||
| 0f00e71b5e | |||
| 44fea0117d | |||
| b9b39a24f7 | |||
| 358fb87683 | |||
| f0ef73d150 | |||
| 1d2297a5fc | |||
| 862736bba4 | |||
| e30dac7cc2 | |||
| f97d5fa232 | |||
| e909616aff | |||
| be219bbee6 | |||
| 17c1c81b4e | |||
| bf0a16c707 | |||
| 86a54feb41 | |||
| 2c923470f8 | |||
| 5d26250b45 | |||
| 6d90e0bf51 | |||
| 51df795a8c | |||
| 9ee053e4f9 | |||
| 4044185ab3 | |||
| f4fe825162 | |||
| cb785b89f0 | |||
| 8289128399 | |||
| e9146f5fc1 | |||
| bc7de458d3 | |||
| 4aa44331f0 | |||
| eada19f516 | |||
| 63677b1451 | |||
| 5789d96a3d | |||
| 0afdeb9bcc | |||
| 79dd8f4e49 | |||
| 93f204ba22 | |||
| 98ad96115a | |||
| ae4ce12c17 | |||
| b8767042b4 | |||
| 200e5f3373 | |||
| ebb68cccfe | |||
| cc4be23802 | |||
| 9f44b1695d | |||
| 94344deff3 | |||
| a41994cb41 | |||
| eee6a713fa | |||
| aed28fe503 | |||
| 7bc72e683b | |||
| 31e386de44 | |||
| 31737efd87 | |||
| be096b9657 | |||
| 3e773ef94b | |||
| 111adc917b | |||
| 6a1b2861f3 | |||
| ed3ff01c22 | |||
| 73e4af98cc | |||
| 84835428ba | |||
| 9f3099ef2b | |||
| 412eed51cd | |||
| bd20d1af02 | |||
| a15932cc7f | |||
| 8942c31a5c | |||
| 90fe6921e2 | |||
| e8a872d351 | |||
| a16ae846ae | |||
| eeaa50ddcb | |||
| 16b0d4eb24 | |||
| e926180605 | |||
| 958b62f8c7 | |||
| d238a9e9dd | |||
| fb993a7060 | |||
| 6b375614ca | |||
| 594cc0f06d | |||
| d712bb1988 | |||
| 59a30238eb | |||
| 8056b66714 | |||
| e09501d779 | |||
| 70192222ad | |||
| cc253d4b33 | |||
| 7d3918a1c6 | |||
| e759a14909 | |||
| fd5a1c5b4b | |||
| c95dc12a96 | |||
| 70ef5912c2 | |||
| 79bb9db3b9 | |||
| d3791ea99b | |||
| 5982fed0b8 | |||
| 1254df2db1 | |||
| 8a23af8581 | |||
| 9cabb27c39 | |||
| 5c17437ba6 | |||
| 520c3659d2 | |||
| 962374b765 | |||
| 8fcc809299 | |||
| 8eac101082 | |||
| b1605ac44e | |||
| 90afc1e221 | |||
| adeba81340 | |||
| 8c10b7ba04 | |||
| 8aae77ff70 | |||
| 7eeacc6268 | |||
| 06e02781d2 | |||
| 3b5625c663 | |||
| ea47f93bc1 | |||
| c33c2de18b | |||
| f125a798bf | |||
| 84d7281002 | |||
| d98a53ec43 | |||
| ee3026233e | |||
| 8fb0b69a79 | |||
| 03ce6c05a9 | |||
| 1d3a03909b | |||
| 7020b78faa | |||
| f1746b41a2 | |||
| 22b96e4b24 | |||
| ddf684f6c6 | |||
| cc9d327ea0 | |||
| 47e23e3463 | |||
| 8feb903021 | |||
| 124172e4d7 | |||
| 9d4367cfac | |||
| 6cd9dfce8c | |||
| 4a3dbe4d60 | |||
| 062ab5045a | |||
| ba472d3b7b | |||
| 82adcf37f4 | |||
| 4f23690ab4 | |||
| 17481aeb38 | |||
| 26adbb1717 | |||
| ffd2785499 | |||
| 5c6d160cbf | |||
| 28a5c5b343 | |||
| 3501fff7fc | |||
| 1988337598 | |||
| be2fdd5cfa | |||
| ef0837c514 | |||
| 252f88e362 | |||
| 8ba9b47141 | |||
| f984339b13 | |||
| a1ff1d2585 | |||
| 3bbe7d0322 | |||
| 3fd729f1a2 | |||
| 375b75c422 | |||
| 340a1e3e3a | |||
| 8d3ab8f93b | |||
| 8dc52de871 | |||
| 6ff39be4bf | |||
| e2548ac9e2 | |||
| 0ce94ada82 | |||
| 77a4c4be70 | |||
| 9616084769 | |||
| 163a246c58 | |||
| 31efcb4a86 | |||
| 1faea596f8 | |||
| cd5cb9093c | |||
| 9f1bd89a0c | |||
| 0908053881 | |||
| 910068bcf5 | |||
| d9ae0ff1bf | |||
| 4bea1a6e70 | |||
| e7873b0fa0 | |||
| c892704ee3 | |||
| 7cd44c853a | |||
| 818b42b97e | |||
| 5870ba98b4 | |||
| 19939c985a | |||
| 7d65a9ef22 | |||
| eb45f7c3bc | |||
| 90a89c9224 | |||
| e59b52dcac | |||
| 07d4edef4e | |||
| b76c2f7b8d | |||
| be414510a4 | |||
| e4b2052231 | |||
| 5066b23603 | |||
| 86de9830b4 | |||
| 758b5e4810 | |||
| 79e2c55c34 | |||
| 802cf51cf9 | |||
| 55d4a90041 | |||
| cf535a2f8f | |||
| ba38964e8a | |||
| c943e5dd43 | |||
| 65f44da4c9 | |||
| 24c51afa40 | |||
| e6739adb35 | |||
| 06fceb07cc | |||
| c87029254c | |||
| d52aca1d3d | |||
| 26af05cd01 | |||
| f7750f2a2c | |||
| 675b4f55c1 | |||
| a322439a83 | |||
| f7a1046c67 | |||
| c17593d932 | |||
| 109d2969a5 | |||
| 2d3c463bf3 | |||
| 74073b641f | |||
| 426033f835 | |||
| a9ad1e22d6 | |||
| 903aa014e4 | |||
| e058854c3f | |||
| c16ce866dc | |||
| f9eba950e0 | |||
| 3eb53d3195 | |||
| 2a5921d3d0 | |||
| 440c711335 | |||
| 7ea573123b | |||
| 7f5ce45fad | |||
| bd16542e25 | |||
| b95a696a5a | |||
| b8f40e8314 | |||
| 0bbeff0b5b | |||
| 5828e16421 | |||
| 8497d2efba | |||
| b578d2ced0 | |||
| 239b461f75 | |||
| c7db7c0926 | |||
| e107766a61 | |||
| 05a0b6c615 | |||
| 7ada8f18fb | |||
| 887a77f4a3 | |||
| 97bde67b1d | |||
| 33c3668175 | |||
| 0158fc3a7a | |||
| 72bb2ddb08 | |||
| 01c1a37fa2 | |||
| 35aa51d6a9 | |||
| ada42ee57d | |||
| fe9b27ecf2 | |||
| e03f120a00 | |||
| 59344f540d | |||
| e829f1fc1b | |||
| d9904eb5f1 | |||
| 10cd26af5e | |||
| c1f649fc83 | |||
| a4865f860d | |||
| 14fce8edfe | |||
| 6826e3567d | |||
| 250e8625a7 | |||
| 58530d6f72 | |||
| 823fb3fca7 | |||
| 29302c0891 | |||
| 03570ebd43 | |||
| 2a4a0d38e3 | |||
| 9be9127ad1 | |||
| 66dd1c01f0 | |||
| d8dce7938d | |||
| 0701f5885e | |||
| ea3f660999 | |||
| 95a21ffe8a | |||
| 89d2cf8340 | |||
| 0eb676d3cd | |||
| ac1a762fa8 | |||
| 59a05262a1 | |||
| 5f91d187c8 | |||
| 8d8bf311ed | |||
| 69545c8a56 | |||
| a1868c0205 | |||
| 12bc4f0da8 | |||
| 510b887042 | |||
| ff7171daa2 | |||
| 5b0dbd5d30 | |||
| 9c7fb25a94 | |||
| 2e24eab5ad | |||
| 8135ad4424 | |||
| 6ffa40e40d | |||
| bc120176ca | |||
| d50d4ae1c9 | |||
| d34aa61e95 | |||
| 04578a4ed1 | |||
| 3e5282a06d | |||
| f86cadb802 | |||
| c4fe4d87db | |||
| 7e5deeaab3 | |||
| 36c425d699 | |||
| a2c69c6144 | |||
| 58e3c0604d | |||
| 7408849eb5 | |||
| b42142f692 | |||
| ddafdcf392 | |||
| 95cbaf1993 | |||
| 43aa3c857d | |||
| 964e0d6f41 | |||
| 5a1c52d3b5 | |||
| 02c374b61e | |||
| f2094e049a | |||
| 8ff2b3b090 | |||
| eeaa363132 | |||
| 43e51848fc | |||
| 8b17117220 | |||
| a4e06a4ce0 | |||
| 4d55f5ebdb | |||
| 268f3c77c2 | |||
| ce73718620 | |||
| d307c58f87 | |||
| e7ec021da8 | |||
| ca94fc7a96 | |||
| 9d650c4885 | |||
| c6d9be499c | |||
| 0e78e8b3f9 | |||
| 2a99278b52 | |||
| 4a47c096f7 | |||
| bd961be055 | |||
| 525fea80b8 | |||
| 6f92ae6a59 | |||
| 8bad6c0f54 | |||
| 91cca16f40 | |||
| a0697a048d | |||
| d22c6aae79 | |||
| 83997980ba | |||
| 4d9bdd1c12 | |||
| 163a73722e | |||
| 65d17decb8 | |||
| 1aa300f97e | |||
| 8fbb30bded | |||
| 6b0f1a0c10 | |||
| 1cee590eca | |||
| 9ff370ee27 | |||
| cd0057ea5a | |||
| 2c0a294b6a | |||
| 3e09bd5c60 | |||
| 0a99d7cebb | |||
| 3138e3edc7 | |||
| 99ab34ad0b | |||
| 9b7923f8f5 | |||
| cfcbe7f107 | |||
| 5fb27ab186 | |||
| 36b1a3c020 | |||
| baccb5d12e | |||
| adc4621711 | |||
| a8d78664e9 | |||
| 9fab4eb088 | |||
| 0d0f1315ff | |||
| 555598c155 | |||
| f49fa23f69 | |||
| b732064f88 | |||
| 1f99a381eb | |||
| 81b610cc4c | |||
| b0a0bfc888 | |||
| 6221ccb53b | |||
| cbe1da2d68 | |||
| 24297e373c | |||
| 99d14a559c | |||
| 08339a1f65 | |||
| 4e3ad38087 | |||
| 63c97fadc6 | |||
| 45633ad7e8 | |||
| 8508decd5c | |||
| 315f47bf30 | |||
| 12f8d79d84 | |||
| 710690e2d2 | |||
| 03bfbe81d0 | |||
| c990fb6fe7 | |||
| 9b31cd63a4 | |||
| dee3ccdf77 | |||
| de23a32c96 | |||
| 2beb840a5c | |||
| f748d76549 | |||
| 9d9a326c2b | |||
| 9184827195 | |||
| cb533c954b | |||
| ead876036d | |||
| cfa25eccb1 | |||
| b0d6233de6 | |||
| b07b8a1aaa | |||
| a68cdaf2ba | |||
| 16641b9193 | |||
| 0469a90992 | |||
| 6dc3e5ab7a | |||
| 82012fa623 | |||
| 7ddd254bb1 | |||
| 464858cfdf | |||
| 30db23255d | |||
| 868c1ef891 | |||
| b961356b7b | |||
| 2e32d6c574 | |||
| a31e5aab79 | |||
| ae4f9565bd | |||
| f33ba10b96 | |||
| 904c519091 | |||
| a0db837910 | |||
| 51cb5db8b4 | |||
| c328728e0c | |||
| 3384ef67a6 | |||
| e89c549706 | |||
| 3c67ac73da | |||
| 656349e6c5 | |||
| df2af0185c | |||
| 913d30f2de | |||
| e96172b698 | |||
| 0c241f683d | |||
| a19097de2b | |||
| f6feeb9d1e | |||
| f205e6f9cc | |||
| 4e543e6068 | |||
| 176062f11c | |||
| 4d88191171 | |||
| 025ea1d094 | |||
| a4283d545a | |||
| 52fa2aace9 | |||
| fa711cf142 | |||
| 70bc7e53fe | |||
| 56f22aa073 | |||
| 878a87278d | |||
| c4a539d2ba | |||
| 4225e81080 | |||
| 8fd4887f10 | |||
| 0e397797b4 | |||
| e6c8458ce7 | |||
| 50ea9919af | |||
| 67f62df894 | |||
| 0da0280156 | |||
| fa713eac4a | |||
| 2c7d56ab34 | |||
| e340268dd0 | |||
| affec6720b | |||
| 5047826a74 | |||
| 33d9230442 | |||
| 607b174c5f | |||
| 6b4ea71404 | |||
| 014322c240 | |||
| b789f84151 | |||
| 19d5fe1ba6 | |||
| 93b95954c4 | |||
| fb7a2aaa32 | |||
| 3105eacd4d | |||
| 215893214f | |||
| 30e01d6700 | |||
| 94cfc5d7d6 | |||
| 471b32cce1 | |||
| 036b34e91d | |||
| 77f7f8c1ed | |||
| e6fc991d2a | |||
| 060881777d | |||
| 6e567fa725 | |||
| 7e4c01937f | |||
| 06a00e6482 | |||
| 242df42f55 | |||
| 8d78c16c8a | |||
| db2b05eb7f | |||
| 282b1090ba | |||
| 4f6c9fa866 | |||
| 9375842c71 | |||
| ea3fca0f1b | |||
| 5971d67a66 | |||
| 357b68dd4f | |||
| 384f3f5698 | |||
| 4577ff9628 | |||
| e6cd9f524d | |||
| 3dad56621f | |||
| 6c9a225b64 | |||
| 3bbb9bd95d | |||
| a4f855ccd8 | |||
| 4d80af4e06 | |||
| 7abce12499 | |||
| 7b1302c011 | |||
| 66d23b7eac | |||
| dc0255509b | |||
| 6661f91eb5 | |||
| 2eb36aedeb | |||
| 0e623ebfeb | |||
| ffb73569e9 | |||
| 713cda9455 | |||
| 223721cca8 | |||
| e7479c8a93 | |||
| 224fe0069b | |||
| cb97847392 | |||
| 6a29531467 | |||
| 262e249d2c | |||
| 77479efaef | |||
| 898863a8d9 | |||
| 05d555f98d | |||
| 868092db10 | |||
| 7a738c2eca | |||
| b304dbcba6 | |||
| 6e28a5daa4 | |||
| 8f4f9660ed | |||
| 2d01535651 | |||
| e57d4669fc | |||
| f47c599dea | |||
| 7a693a90f7 | |||
| 9cf51de3f7 | |||
| 5089c20cd6 | |||
| a0da23f86a | |||
| 44d24b57c6 | |||
| c143d774d4 | |||
| 9e92240dd0 | |||
| d2c586b096 | |||
| fbfbb9408a | |||
| fb56665dec | |||
| 5b65c216b6 | |||
| 9ad98c5970 | |||
| cae9d0f2e5 | |||
| c0d267c63e | |||
| 70704b0a5e | |||
| b135275201 | |||
| 7e1eae6681 | |||
| 30f5d6dc85 | |||
| a50dd1168b | |||
| 62fa1620aa | |||
| a0d42c8b59 | |||
| a21663da61 | |||
| 67a0382942 | |||
| f5c2467d01 | |||
| a3abcc8094 | |||
| edf439f301 | |||
| 2245563250 | |||
| bca21d5515 | |||
| 89cae2e7c9 | |||
| 26c381a4c4 | |||
| 4bc5aa050c | |||
| cd44b0d180 | |||
| 59ee91ca5d | |||
| 59165a7033 | |||
| 93d242c05f | |||
| 4bbb6591e3 | |||
| 7df8025f6a | |||
| f19c52f40e | |||
| b7840779fe | |||
| 28042a8cc9 | |||
| b2907226bf | |||
| a2f46821f5 | |||
| b7385cd4cc | |||
| 718c65818c | |||
| 91e2293606 | |||
| 3c4a921f9a | |||
| d04b333126 | |||
| 0a4bef4d9a | |||
| a0f090a83a | |||
| dc8ee5943c | |||
| 9132c36aa7 | |||
| 224c0d759f | |||
| ffcaca2db1 | |||
| 409fc4a43b | |||
| 16968f3f2b | |||
| e3fd0dce21 | |||
| 53b6b6deca | |||
| 26f47a50d0 | |||
| 3cf77374c4 | |||
| a1129c3f0f | |||
| 2fe74603a3 | |||
| 54d517363d | |||
| 948fe0c0e6 | |||
| dbd8e6c0e9 | |||
| 02b5601933 | |||
| 3ed40608a2 | |||
| 36d7c2dd91 | |||
| fa7ef68851 | |||
| f84877a4fc | |||
| 261fb62e24 | |||
| 48d8aa4cd8 | |||
| 95ff0d3db6 | |||
| 2dc1d914c0 | |||
| fc06701009 | |||
| ee4f334296 | |||
| cac2395237 | |||
| 5afc3f13cf | |||
| 9030917c14 | |||
| 9905def352 | |||
| a3793aa92b | |||
| 76c8498956 | |||
| 75bd8ea5a2 | |||
| 50a5e864ac | |||
| 352fc26f7e | |||
| 44afa1623e | |||
| 14acafabfc | |||
| 773af58d03 | |||
| 352b851e9c | |||
| 8353a01082 | |||
| b70e001206 | |||
| a741bb4d55 | |||
| 24adee3d54 | |||
| 09203ffb95 | |||
| e94338f4c6 | |||
| dd9dd8ee81 | |||
| 01d6dcac59 | |||
| ad0ee6b0d6 | |||
| 769c8c228e | |||
| 50fcd67085 | |||
| 52d03e6b7d | |||
| b949cd0039 | |||
| e527170315 | |||
| ec7d210c36 | |||
| 74a4089464 | |||
| fa9e14f574 | |||
| cdbeefcd16 | |||
| ffdd5f4091 | |||
| bb60525780 | |||
| 82634af649 | |||
| 3643ed9f13 | |||
| fac59ab705 | |||
| 1e343b0d12 | |||
| 34bb467b97 | |||
| b092525c10 | |||
| 256dac3a82 | |||
| dfe947f54d | |||
| ce09407816 | |||
| beee6af79d | |||
| c282562867 | |||
| 2aed9b3a33 | |||
| 210910f21e | |||
| 1d666318ae | |||
| 4df6095089 | |||
| d4edcce224 | |||
| d7c6761841 | |||
| 5733224f8d | |||
| 22fd5042bc | |||
| 44a6f2d448 | |||
| cd9c17f9b3 | |||
| dc07bcf0fa | |||
| 248b8fb4fd | |||
| d5ec7c3001 | |||
| 35182a1483 | |||
| 21b0a517a9 | |||
| 19a770445e | |||
| c6512f1376 | |||
| 2cb3963138 | |||
| d05c394c68 | |||
| 797de31960 | |||
| a0af1a811a | |||
| 4933b9ce54 | |||
| e81c4eb155 | |||
| b284c8bc56 | |||
| 872d2d4337 | |||
| 525f1b7781 | |||
| 2f99d8ca62 | |||
| 7781014cf7 | |||
| 2432b36f5d | |||
| 288aa015fa | |||
| 1cb8b922c3 | |||
| 41cec64bf6 | |||
| d82bda9d00 | |||
| b84da40365 | |||
| d02c947b84 | |||
| 7167a5a71e | |||
| f13c2455ea | |||
| b200b66612 | |||
| b811df8cda | |||
| 1e239b78c3 | |||
| 3a8daadd92 | |||
| f605d6fca5 | |||
| cd85e43624 | |||
| 2b94d09539 | |||
| ab82da5c75 | |||
| 8a467aa537 | |||
| 742e6b1e3e | |||
| e35e8bcdce | |||
| 5f953aa47f | |||
| e550e9aa1d | |||
| 26e2defd9e | |||
| 3b3641c69e | |||
| 56ccd518d6 | |||
| 59846280a8 | |||
| aa95e3abcd | |||
| ad6340c1a7 | |||
| 62a54aab58 | |||
| 23f1e81cf0 | |||
| d014f422d2 | |||
| 68a9f1bc46 | |||
| 798637d465 | |||
| 60ea4c5f77 | |||
| 0e119950c2 | |||
| 4be4467fc6 | |||
| 06636b2a28 | |||
| 71a36d1b25 | |||
| 9ba93ff8d2 | |||
| 4059308dd7 | |||
| 9befe8ae5f | |||
| 20e01f3b2c | |||
| 98b894ed8e | |||
| ac8b7264b3 | |||
| bf7b24ecc0 | |||
| 9f43dd2db5 | |||
| 28d868985e | |||
| cf1be26da2 | |||
| 1de9b73aa0 | |||
| 3532a6360b | |||
| beddc8e1ea | |||
| df81fba565 | |||
| 25da0d26ef | |||
| e0c34d20a8 | |||
| cc6db5b5cc | |||
| c38df03add | |||
| 63402358d1 | |||
| 3ae1de735e | |||
| a701eb0e4f | |||
| 09caf017a9 | |||
| 32b8b2093d | |||
| c84a4f1aa8 | |||
| d90c0b5431 | |||
| 94f6785f0d | |||
| f01c382807 | |||
| 6d42803dd8 | |||
| 61e908ccb5 | |||
| 236bcba2bd | |||
| 7bae8c34a7 | |||
| 3960341640 | |||
| 06e453dd05 | |||
| 0347877290 | |||
| b464526d5e | |||
| 361b1cbad4 | |||
| 56a866fca7 | |||
| 49e0d68374 | |||
| 0ccd05e605 | |||
| 916e4586c5 | |||
| c9ffd0b4bb | |||
| 1d2f6f46a4 | |||
| 4af6d856b9 | |||
| 6fd4294391 | |||
| 88b2b85f2a | |||
| 2c1dff6ac8 | |||
| 481b42f563 | |||
| 597c321009 | |||
| 76651f75d8 | |||
| 3d8bae55a1 | |||
| 4b6869e367 | |||
| 477ba7c081 | |||
| 5b6d9725b8 | |||
| 25c3cea115 | |||
| d90601276f | |||
| 4f692bc698 | |||
| d8dd02eef0 | |||
| 8ad65ae233 | |||
| eabbb4569b | |||
| 49888b771d | |||
| 2b1c1cd052 | |||
| 61884e67ec | |||
| 9a2f028843 | |||
| 2b56acf164 | |||
| 98b67dcc28 | |||
| 500dfa3107 | |||
| c4efcfd2db | |||
| 81ee6bbcf6 | |||
| e4e2e76e06 | |||
| f847862e84 | |||
| 427dbeafde | |||
| 99ac85b40e | |||
| 020388baed | |||
| 4ade79de4f | |||
| 870dda9b8b | |||
| 27dd5298f7 | |||
| 6d5d406ce9 | |||
| ffb5e7e6f7 | |||
| 0de101c89f | |||
| bd3a0766e1 | |||
| f536cc8f8a | |||
| 826c0495fc | |||
| 9eac541ce5 |
+1
-1
@@ -3,8 +3,8 @@
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry kind="lib" path="libs/googleloginclient-helper.jar"/>
|
||||
<classpathentry kind="lib" path="libs/google-common.jar"/>
|
||||
<classpathentry kind="lib" path="libs/accounts.jar"/>
|
||||
<classpathentry kind="lib" path="libs/google-api-client-1.2.2-alpha.jar"/>
|
||||
<classpathentry kind="lib" path="libs/libGoogleAnalytics.jar"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry exported="true" kind="lib" path="/MyTracksLib/libs/protobuf-java-2.3.0-lite.jar"/>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<name>MyTracks</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
<project>MyTracksLib</project>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#Wed Sep 29 18:44:16 BRT 2010
|
||||
#Thu Jul 21 03:01:59 BRT 2011
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
@@ -7,6 +7,343 @@ org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deadCode=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
|
||||
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
|
||||
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.nullReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
|
||||
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=48
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=48
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=48
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_source_code=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.line_length=80
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation=2
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
|
||||
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
|
||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=true
|
||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
|
||||
org.eclipse.jdt.core.formatter.indentation.size=4
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
|
||||
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true
|
||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.lineSplit=80
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=space
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=2
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=false
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#Thu Jul 21 03:04:13 BRT 2011
|
||||
eclipse.preferences.version=1
|
||||
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
|
||||
formatter_profile=_MyTracks
|
||||
formatter_settings_version=12
|
||||
org.eclipse.jdt.ui.ignorelowercasenames=true
|
||||
org.eclipse.jdt.ui.importorder=com;android;java;javax;org;
|
||||
org.eclipse.jdt.ui.ondemandthreshold=99
|
||||
org.eclipse.jdt.ui.staticondemandthreshold=99
|
||||
sp_cleanup.add_default_serial_version_id=true
|
||||
sp_cleanup.add_generated_serial_version_id=false
|
||||
sp_cleanup.add_missing_annotations=true
|
||||
sp_cleanup.add_missing_deprecated_annotations=true
|
||||
sp_cleanup.add_missing_methods=false
|
||||
sp_cleanup.add_missing_nls_tags=false
|
||||
sp_cleanup.add_missing_override_annotations=true
|
||||
sp_cleanup.add_missing_override_annotations_interface_methods=true
|
||||
sp_cleanup.add_serial_version_id=false
|
||||
sp_cleanup.always_use_blocks=true
|
||||
sp_cleanup.always_use_parentheses_in_expressions=false
|
||||
sp_cleanup.always_use_this_for_non_static_field_access=false
|
||||
sp_cleanup.always_use_this_for_non_static_method_access=false
|
||||
sp_cleanup.convert_to_enhanced_for_loop=false
|
||||
sp_cleanup.correct_indentation=false
|
||||
sp_cleanup.format_source_code=false
|
||||
sp_cleanup.format_source_code_changes_only=false
|
||||
sp_cleanup.make_local_variable_final=false
|
||||
sp_cleanup.make_parameters_final=false
|
||||
sp_cleanup.make_private_fields_final=true
|
||||
sp_cleanup.make_type_abstract_if_missing_method=false
|
||||
sp_cleanup.make_variable_declarations_final=true
|
||||
sp_cleanup.never_use_blocks=false
|
||||
sp_cleanup.never_use_parentheses_in_expressions=true
|
||||
sp_cleanup.on_save_use_additional_actions=false
|
||||
sp_cleanup.organize_imports=true
|
||||
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
|
||||
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
|
||||
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
|
||||
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
|
||||
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
|
||||
sp_cleanup.remove_private_constructors=true
|
||||
sp_cleanup.remove_trailing_whitespaces=false
|
||||
sp_cleanup.remove_trailing_whitespaces_all=true
|
||||
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
|
||||
sp_cleanup.remove_unnecessary_casts=true
|
||||
sp_cleanup.remove_unnecessary_nls_tags=false
|
||||
sp_cleanup.remove_unused_imports=false
|
||||
sp_cleanup.remove_unused_local_variables=false
|
||||
sp_cleanup.remove_unused_private_fields=true
|
||||
sp_cleanup.remove_unused_private_members=false
|
||||
sp_cleanup.remove_unused_private_methods=true
|
||||
sp_cleanup.remove_unused_private_types=true
|
||||
sp_cleanup.sort_members=false
|
||||
sp_cleanup.sort_members_all=false
|
||||
sp_cleanup.use_blocks=false
|
||||
sp_cleanup.use_blocks_only_for_return_and_throw=false
|
||||
sp_cleanup.use_parentheses_in_expressions=false
|
||||
sp_cleanup.use_this_for_non_static_field_access=false
|
||||
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
|
||||
sp_cleanup.use_this_for_non_static_method_access=false
|
||||
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
|
||||
+129
-41
@@ -17,8 +17,8 @@ limitations under the License.
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.maps.mytracks"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="28"
|
||||
android:versionName="1.1.5">
|
||||
android:versionCode="32"
|
||||
android:versionName="1.1.9">
|
||||
<application android:icon="@drawable/arrow_icon"
|
||||
android:label="@string/app_name"
|
||||
android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent">
|
||||
@@ -44,6 +44,120 @@ limitations under the License.
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:mimeType="vnd.android.cursor.item/vnd.google.track" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.MapActivity"
|
||||
android:label="MyTracks"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<category android:name="android.intent.category.TAB" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.MyMapsList"
|
||||
android:label="@string/map_list_title"
|
||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- TODO: VIEW and PICK for track cursor dir -->
|
||||
<activity android:name="com.google.android.apps.mytracks.TrackList"
|
||||
android:label="Recorded Tracks" />
|
||||
|
||||
<!-- TODO: VIEW and PICK for waypoint cursor dir -->
|
||||
<activity android:name="com.google.android.apps.mytracks.WaypointsList"
|
||||
android:label="Recorded Waypoints" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.TrackDetails"
|
||||
android:label="@string/trackdetails_title">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.EDIT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:mimeType="vnd.android.cursor.item/vnd.google.track" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.DeleteTrack"
|
||||
android:label="@string/deletetrack_title"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:noHistory="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.DELETE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="vnd.android.cursor.item/vnd.google.track" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.WaypointDetails"
|
||||
android:label="@string/waypointdetails_title">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.intent.action.EDIT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:mimeType="vnd.android.cursor.item/vnd.google.waypoint" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.SettingsActivity"
|
||||
android:label="@string/mytracks_settings" >
|
||||
<intent-filter>
|
||||
<category android:name="android.intent.category.PREFERENCE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.AggregatedStatsActivity"
|
||||
android:label="@string/aggregated_stats" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.StatsActivity"
|
||||
android:label="@string/statistics"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<category android:name="android.intent.category.TAB" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.SensorStateActivity"
|
||||
android:label="@string/sensor_state" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.ChartActivity"
|
||||
android:label="@string/elevation_label"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<category android:name="android.intent.category.TAB" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.SendActivity"
|
||||
android:label="@string/sendtogoogle_title"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<data android:mimeType="vnd.android.cursor.item/vnd.google.track" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.io.file.SaveActivity"
|
||||
android:label="@string/tracklist_write_to_sd"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:noHistory="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SAVE" />
|
||||
<data android:mimeType="vnd.android.cursor.item/vnd.google.track" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.io.file.ImportActivity"
|
||||
android:label="@string/import_title"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:noHistory="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.intent.action.ATTACH_DATA" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="file" />
|
||||
<data android:mimeType="application/gpx+xml" />
|
||||
<data android:mimeType="application/gpx" />
|
||||
@@ -52,44 +166,6 @@ limitations under the License.
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.MapActivity"
|
||||
android:label="MyTracks"
|
||||
android:exported="false" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.MyMapsList"
|
||||
android:label="@string/map_list_title"
|
||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale"
|
||||
android:exported="false" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.TrackList"
|
||||
android:label="Recorded Tracks" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.WaypointsList"
|
||||
android:label="Recorded Waypoints" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.TrackDetails"
|
||||
android:label="@string/trackdetails_title" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.WaypointDetails"
|
||||
android:label="@string/waypointdetails_title" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.SettingsActivity"
|
||||
android:label="@string/mytracks_settings" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.AggregatedStatsActivity"
|
||||
android:label="@string/aggregated_stats" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.StatsActivity"
|
||||
android:label="@string/statistics"
|
||||
android:exported="false" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.SensorStateActivity"
|
||||
android:label="@string/sensor_state" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.ChartActivity"
|
||||
android:label="@string/elevation_label"
|
||||
android:exported="false" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.WelcomeActivity"
|
||||
android:label="@string/welcome"
|
||||
android:exported="false" />
|
||||
@@ -104,7 +180,18 @@ limitations under the License.
|
||||
<receiver android:name="com.google.android.apps.mytracks.BootReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="com.google.android.apps.mytracks.widgets.TrackWidgetProvider">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
<action android:name="com.google.android.apps.mytracks.TRACK_STARTED" />
|
||||
<action android:name="com.google.android.apps.mytracks.TRACK_STOPPED" />
|
||||
<action android:name="com.google.android.apps.mytracks.TRACK_UPDATED" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.appwidget.provider"
|
||||
android:resource="@xml/track_widget_info" />
|
||||
</receiver>
|
||||
</application>
|
||||
|
||||
@@ -114,6 +201,7 @@ limitations under the License.
|
||||
<!-- Permissions for recording tracks and showing maps -->
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# Indicates whether an apk should be generated for each density.
|
||||
split.density=false
|
||||
# Project target.
|
||||
target=Google Inc.:Google APIs:11
|
||||
target=Google Inc.:Google APIs:13
|
||||
android.library.reference.1=../MyTracksLib/
|
||||
|
||||
# ProGuard is turned off while we investigate the removal of code that
|
||||
|
||||
@@ -5,9 +5,6 @@ licenses or the JAR's authors.
|
||||
|
||||
References are provided to the libraries:
|
||||
|
||||
accounts.jar (Android accounts library):
|
||||
http://code.google.com/p/libs-for-android/wiki/AccountsLibrary
|
||||
|
||||
google-api-client-*.jar (GData client):
|
||||
http://code.google.com/p/google-api-java-client/
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2011 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:paddingLeft="10px"
|
||||
android:paddingRight="10px"
|
||||
android:paddingTop="5px"
|
||||
android:paddingBottom="5px">
|
||||
<LinearLayout
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="fill_parent"
|
||||
android:background="@drawable/appwidget_background">
|
||||
<ImageButton
|
||||
android:id="@+id/appwidget_button"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:paddingLeft="10px"
|
||||
android:paddingRight="10px"
|
||||
android:src="@drawable/appwidget_button_disabled" />
|
||||
<LinearLayout
|
||||
android:id="@+id/appwidget_track_statistics"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:clickable="true"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="15px">
|
||||
<LinearLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
style="@style/WidgetText.Register"
|
||||
android:id="@+id/appwidget_distance_text" />
|
||||
<TextView
|
||||
style="@style/WidgetText"
|
||||
android:text="@string/total_distance_label" />
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1px"
|
||||
android:background="@color/appwidget_hr" />
|
||||
<LinearLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="2px">
|
||||
<TextView
|
||||
style="@style/WidgetText.Register"
|
||||
android:id="@+id/appwidget_time_text" />
|
||||
<TextView
|
||||
style="@style/WidgetText"
|
||||
android:text="@string/moving_time_label" />
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1px"
|
||||
android:background="@color/appwidget_hr" />
|
||||
<LinearLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
style="@style/WidgetText.Register"
|
||||
android:id="@+id/appwidget_speed_text" />
|
||||
<TextView
|
||||
style="@style/WidgetText"
|
||||
android:text="@string/speed" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -284,11 +284,4 @@ limitations under the License.
|
||||
<item>punt de referència</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>Cap</item>
|
||||
<item>ANT+ Sensors</item>
|
||||
<item>SRM ANT+ Bridge</item>
|
||||
<item>Zephyr Bluetooth</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -409,4 +409,6 @@ limitations under the License.
|
||||
<string name="searching">S\'està cercant</string>
|
||||
<string name="sending">S\'està enviant</string>
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">Cap</string>
|
||||
</resources>
|
||||
|
||||
@@ -143,11 +143,4 @@ limitations under the License.
|
||||
<item>camino</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>Ninguna</item>
|
||||
<item>ANT+ Sensores</item>
|
||||
<item>SRM ANT+ Puente</item>
|
||||
<item>Zephyr Bluetooth</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -128,4 +128,8 @@ limitations under the License.
|
||||
$6 : Speed units (mph) : Pace units (per mile)
|
||||
-->
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">Ninguna</string>
|
||||
<string name="ant_sensor_option">ANT+ Sensores</string>
|
||||
<string name="ant_bridge_sensor_option">SRM ANT+ Puente</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<!-- Minimum recording distance -->
|
||||
<string-array name="min_recording_distance_options">
|
||||
<item>1 m</item>
|
||||
<item>2 m</item>
|
||||
<item>3 m</item>
|
||||
<item>4 m</item>
|
||||
<item>5 m (suositeltu)</item>
|
||||
<item>10 m</item>
|
||||
<item>100 m</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="min_recording_distance_options_ft">
|
||||
<item>3 ft</item>
|
||||
<item>6 ft</item>
|
||||
<item>10 ft</item>
|
||||
<item>13 ft</item>
|
||||
<item>16 ft (suositeltu)</item>
|
||||
<item>33 ft</item>
|
||||
<item>328 ft</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Maximum recording distance -->
|
||||
<string-array name="max_recording_distance_options">
|
||||
<item>50 m</item>
|
||||
<item>100 m</item>
|
||||
<item>200 m (suositeltu)</item>
|
||||
<item>500 m</item>
|
||||
<item>1000 m</item>
|
||||
<item>5000 m</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="max_recording_distance_options_ft">
|
||||
<item>164 ft</item>
|
||||
<item>328 ft</item>
|
||||
<item>656 ft (suositeltu)</item>
|
||||
<item>1640 ft</item>
|
||||
<item>0.6 mailia</item>
|
||||
<item>3.1 mailia</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Minimum recording interval -->
|
||||
<string-array name="min_recording_interval_options">
|
||||
<item>virransäästö (mukautuva)</item>
|
||||
<item>paras tarkkuus (mukautuva)</item>
|
||||
<item>nopein (suositeltu)</item>
|
||||
<item>2 s</item>
|
||||
<item>3 s</item>
|
||||
<item>4 s</item>
|
||||
<item>5 s</item>
|
||||
<item>10 s</item>
|
||||
<item>20 s</item>
|
||||
<item>30 s</item>
|
||||
<item>1 min</item>
|
||||
<item>2 min</item>
|
||||
<item>5 min</item>
|
||||
<item>10 min</item>
|
||||
<item>15 min</item>
|
||||
<item>30 min</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Minimum required accuracy -->
|
||||
<string-array name="min_required_accuracy_options">
|
||||
<item>10 m (erinomainen GPS-signaali)</item>
|
||||
<item>20 m</item>
|
||||
<item>50 m</item>
|
||||
<item>100 m</item>
|
||||
<item>200 m (suositeltu)</item>
|
||||
<item>500 m</item>
|
||||
<item>1000 m</item>
|
||||
<item>2000 m</item>
|
||||
<item>5000 m (heikko GPS-signaali)</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="min_required_accuracy_options_ft">
|
||||
<item>33 ft (erinomainen GPS-signaali)</item>
|
||||
<item>66 ft</item>
|
||||
<item>165 ft</item>
|
||||
<item>328 ft</item>
|
||||
<item>656 ft (suositeltu)</item>
|
||||
<item>1640 ft</item>
|
||||
<item>0.6 mailia</item>
|
||||
<item>1.2 mailia</item>
|
||||
<item>3.1 mailia (heikko GPS-signaali)</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Task frequency -->
|
||||
<string-array name="task_frequency_options">
|
||||
<item>Pois päältä</item>
|
||||
<item>100 km</item>
|
||||
<item>50 km</item>
|
||||
<item>25 km</item>
|
||||
<item>10 km</item>
|
||||
<item>5 km</item>
|
||||
<item>1 km</item>
|
||||
<item>60 min</item>
|
||||
<item>30 min</item>
|
||||
<item>15 min</item>
|
||||
<item>10 min</item>
|
||||
<item>5 min</item>
|
||||
<item>2 min</item>
|
||||
<item>1 min</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="task_frequency_options_ft">
|
||||
<item>Pois päältä</item>
|
||||
<item>100 mi</item>
|
||||
<item>50 mi</item>
|
||||
<item>25 mi</item>
|
||||
<item>10 mi</item>
|
||||
<item>5 mi</item>
|
||||
<item>1 mi</item>
|
||||
<item>60 min</item>
|
||||
<item>30 min</item>
|
||||
<item>15 min</item>
|
||||
<item>10 min</item>
|
||||
<item>5 min</item>
|
||||
<item>2 min</item>
|
||||
<item>1 min</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Auto-resume track timeout -->
|
||||
<string-array name="auto_resume_track_timeout_options">
|
||||
<item>Ei koskaan</item>
|
||||
<item>5 min</item>
|
||||
<item>10 min</item>
|
||||
<item>15 min</item>
|
||||
<item>Aina</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Other non-preference arrays -->
|
||||
<array name="activity_types">
|
||||
<item>tuntematon</item>
|
||||
<item>sekoitus</item>
|
||||
<item>muu</item>
|
||||
|
||||
<item>juoksu</item>
|
||||
<item>katujuoksu</item>
|
||||
<item>ratajuoksu</item>
|
||||
<item>maastojuoksu</item>
|
||||
<item>kävely</item>
|
||||
<item>hölkkä</item>
|
||||
<item>patikointi</item>
|
||||
<item>patikointi metsässä</item>
|
||||
<item>suokävely</item>
|
||||
<item>kiipeily</item>
|
||||
|
||||
<item>pyöräily</item>
|
||||
<item>maantiepyöräily</item>
|
||||
<item>maastopyöräily</item>
|
||||
<item>ratapyöräily</item>
|
||||
|
||||
<item>luistelu</item>
|
||||
<item>rullaluistelu</item>
|
||||
<item>rullalautailu</item>
|
||||
|
||||
<item>rullahiihto (classic)</item>
|
||||
<item>rullahiihto (skate)</item>
|
||||
<item>maastohiihto (classic)</item>
|
||||
<item>maastohiihto (skate)</item>
|
||||
|
||||
<item>lumikävely</item>
|
||||
<item>hiihto</item>
|
||||
<item>lumilautailu</item>
|
||||
<item>kelkkailu</item>
|
||||
<item>jääpurjehdus</item>
|
||||
|
||||
<item>purjehdus</item>
|
||||
<item>melonta</item>
|
||||
<item>soutu</item>
|
||||
<item>moottoriveneily</item>
|
||||
<item>lautta</item>
|
||||
<item>RC-veneily</item>
|
||||
<item>surffaus</item>
|
||||
<item>purjelautailu</item>
|
||||
<item>vesihiito</item>
|
||||
<item>wake boarding</item>
|
||||
|
||||
<item>lentokone</item>
|
||||
<item>katamaraani</item>
|
||||
<item>liikennelentokone</item>
|
||||
<item>helikopteri</item>
|
||||
<item>kuumailmapallo</item>
|
||||
<item>ilmalaiva</item>
|
||||
<item>RC-lennokki</item>
|
||||
<item>RC-helikopteri</item>
|
||||
<item>laskuvarjohyppy</item>
|
||||
<item>liitovarjo</item>
|
||||
|
||||
<item>ratsastus</item>
|
||||
|
||||
<item>autolla ajo</item>
|
||||
<item>bussimatka</item>
|
||||
<item>juna</item>
|
||||
<item>moottoripyörä</item>
|
||||
<item>maastopyörä</item>
|
||||
<item>ATV</item>
|
||||
|
||||
<item>maapurjehdus</item>
|
||||
<item>frisbee</item>
|
||||
<item>ultimate frisbee</item>
|
||||
</array>
|
||||
|
||||
<array name="waypoint_types">
|
||||
<item>baari</item>
|
||||
<item>bussipysäkki</item>
|
||||
<item>cafe</item>
|
||||
<item>golfrata</item>
|
||||
<item>grilli</item>
|
||||
<item>hotelli</item>
|
||||
<item>huoltoasema</item>
|
||||
<item>information</item>
|
||||
<item>juomavesi</item>
|
||||
<item>kahvila</item>
|
||||
<item>kalastus</item>
|
||||
<item>kampaamo</item>
|
||||
<item>kauppa</item>
|
||||
<item>kirkko</item>
|
||||
<item>kohtaamispaikka</item>
|
||||
<item>kuoppa</item>
|
||||
<item>lautta</item>
|
||||
<item>marketti</item>
|
||||
<item>nuotio</item>
|
||||
<item>nähtävyys</item>
|
||||
<item>putoavia kiviä</item>
|
||||
<item>paloasema</item>
|
||||
<item>postilaatikko</item>
|
||||
<item>ooppera</item>
|
||||
<item>ostokset</item>
|
||||
<item>pankkiautomaatti</item>
|
||||
<item>pankki</item>
|
||||
<item>poliisiasema</item>
|
||||
<item>pysäköinti</item>
|
||||
<item>posti</item>
|
||||
<item>puhelin</item>
|
||||
<item>puu</item>
|
||||
<item>rakennus</item>
|
||||
<item>ravintola</item>
|
||||
<item>reittipiste</item>
|
||||
<item>retkeilyreitti</item>
|
||||
<item>risteys</item>
|
||||
<item>ruokakauppa</item>
|
||||
<item>satama</item>
|
||||
<item>talo</item>
|
||||
<item>tasoristeys</item>
|
||||
<item>teatteri</item>
|
||||
<item>tulentekopaikka</item>
|
||||
<item>tunneli</item>
|
||||
<item>turisti-info</item>
|
||||
<item>uima-allas</item>
|
||||
<item>vesiputous</item>
|
||||
<item>WC</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,510 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<!-- Used by the Menu -->
|
||||
<string name="start_recording">Aloita reitti</string>
|
||||
<string name="stop_recording">Lopeta</string>
|
||||
<string name="switch_to_sat">Satelliitti</string>
|
||||
<string name="switch_to_map">Kartta</string>
|
||||
<string name="mylocation">Oma sijainti</string>
|
||||
<string name="list_tracks">Reitit</string>
|
||||
<string name="list_markers">Merkinnät</string>
|
||||
<string name="delete_all_tracks">Poista kaikki reitit</string>
|
||||
<string name="settings">Asetukset</string>
|
||||
<string name="elevation">Korkeus</string>
|
||||
<string name="choose_track_message">Valitse näytettävä reitti</string>
|
||||
<string name="current_track">Valittu reitti</string>
|
||||
<string name="current_segment">Nykyinen segmentti</string>
|
||||
<string name="sensor_state">Sensorien tila</string>
|
||||
<string name="aggregated_stats">Yhteenlasketut tilastot</string>
|
||||
|
||||
<!-- Error messages -->
|
||||
<string name="error_no_location_manager">Paikkatietoja ei löytynyt!</string>
|
||||
<string name="error_no_gps_location_provider">GPS-palvelua ei löytynyt.</string>
|
||||
<string name="error_sending_to_mymap">Virhe lähetettäessä reittiä Google My Maps-palveluun.</string>
|
||||
<string name="error_sending_to_fusiontables">Virhe lähetettäessä reittiä Google Fusion Tables-palveluun.</string>
|
||||
<string name="error_sending_to_docs">Virhe lähetettäessä reittiä Google Docs-palveluun..</string>
|
||||
<string name="error_please_try_again_later">Yritä myöhemmin uudelleen.</string>
|
||||
<string name="error_unable_to_start_recording">Tallennusta ei voitu aloittaa. Yritä uudelleen.</string>
|
||||
<string name="error_unable_to_stop_recording">Tallennusta ei voitu pysäyttää. Yritä uudelleen.</string>
|
||||
<string name="error_unable_to_read_file">Tiedostovirhe.</string>
|
||||
<string name="error_invalid_gpx_format">Virheellinen GPX-formaatti.</string>
|
||||
<string name="error_generic">Tapahtui virhe. Yritä uudelleen.</string>
|
||||
<string name="error_track_does_not_exist">Reittiä ei ole olemassa.</string>
|
||||
<string name="error_operation_cancelled">Tapahtuma keskeytettiin.</string>
|
||||
<string name="error_out_of_memory">Liian suuri tiedosto (maksimi 500 KB). Keskeytetään.</string>
|
||||
<string name="error_unable_to_insert_marker">Merkintää ei voitu lisätä. Paikkatietoa ei saatavilla.</string>
|
||||
|
||||
<!-- Status messages -->
|
||||
<string name="wait_for_fix">Odotetaan parempaa GPS-yhteyttä. Varmista että taivas on näkyvissä.</string>
|
||||
<string name="status_now_recording">Tallennetaan uutta reittiä.</string>
|
||||
<string name="status_stopped_recording">Reitin tallentaminen lopetettiin.</string>
|
||||
<string name="status_new_mymap_has_been_created">Uusi Google My Map on luotu osoitteeseen maps.google.com.</string>
|
||||
<string name="status_new_fusiontable_has_been_created">Uusi Google Fusion taulukko on luotu osoitteeseen google.com/fusiontables.</string>
|
||||
<string name="status_tracks_have_been_uploaded">Reittisi on lähetetty osoitteeseen maps.google.com.</string>
|
||||
<string name="status_tracks_have_been_uploaded_to_new_doc">Reittisi on luotu taulukoksi osoitteeseen docs.google.com.</string>
|
||||
<string name="status_tracks_have_been_uploaded_to_docs">Reittisi on lähetetty osoitteeseen docs.google.com.</string>
|
||||
<string name="status_mymap_info">Reitin näkyminen saattaa kestää muutaman minuutin.</string>
|
||||
<string name="status_enable_gps">Avaa tästä Sijainti ja suojaus -asetukset ja valitse \'Käytä GPS-satelliitteja\'. Palaa ohjelmaan painamalla Takaisin-näppäintä.</string>
|
||||
<string name="status_approximate_location">Huomio: Näkyvä sijainti perustuu kännykkämastoista ja WLAN-verkoista arvioituun paikkatietoon.</string>
|
||||
<string name="status_no_location">Paikkatietoa ei löydy. Aktivoi lisää paikannusmenetelmiä (katso Asetukset) ja varmista että taivas on näkyvissä. Yritä myöhemmin uudelleen.</string>
|
||||
<string name="status_waypoint_inserted">Reittimerkintä lisätty.</string>
|
||||
<string name="status_statistics_inserted">Tilastomerkintä lisätty.</string>
|
||||
<string name="status_track_upload_status">Lähetyksen tila:</string>
|
||||
|
||||
<!-- Progress dialog -->
|
||||
<string name="progress_title">Odota...</string>
|
||||
<string name="progress_message">Lähetetään reittiä Google:n palvelimelle.</string>
|
||||
<string name="progress_message_reading_track">Luetaan reittiä...</string>
|
||||
<string name="progress_message_preparing_track">Valmistellaan reittiä...</string>
|
||||
<string name="progress_message_authenticating_fusiontables">Todennetaan Google Fusion Tables -tiliä...</string>
|
||||
<string name="progress_message_authenticating_mymaps">Todennetaan Google Maps -tiliä...</string>
|
||||
<string name="progress_message_authenticating_docs">Todennetaan Google Docs -tiliä...</string>
|
||||
<string name="progress_message_sending_docs">Lähetetään reittiä Google Docsiin...</string>
|
||||
<string name="progress_message_sending_mymaps">Lähetetään reittiä Google Mapsiin...</string>
|
||||
<string name="progress_message_creating_map">Luodaan uutta My Mapsia...</string>
|
||||
<string name="progress_message_sending_fusiontables">Lähetetään reittiä Fusion Tablesiin...</string>
|
||||
<string name="progress_message_creating_fusiontable">Luodaan uutta Fusion tablea...</string>
|
||||
<string name="import_progress_message">Tuodaan uutta GPS-reittiä. Odota.</string>
|
||||
<string name="write_progress_message">Kirjoitetaan tiedostoa SD-kortille. Odota.</string>
|
||||
<string name="progress_message_updating_track">Päivitetään reitin tilastoja...</string>
|
||||
|
||||
<!-- Used by DeleteAllDataHandler -->
|
||||
<string name="are_you_sure_question">Oletko varma?</string>
|
||||
<string name="all_data_will_be_permanently_deleted">Kaikki reitit ja merkinnät poistetaan puhelimesta.</string>
|
||||
<string name="track_will_be_permanently_deleted">Reitti ja se merkinnät poistetaan pysyvästi puhelimesta.</string>
|
||||
<string name="marker_will_be_permanently_deleted">Merkintä poistetaan puhelimesta.</string>
|
||||
|
||||
<!-- Text and links when uploading to Google Fusion Tables -->
|
||||
<string name="new_map_description">Created by My Tracks on Android.</string>
|
||||
<string name="fusiontable_link">Created by <a href=\'http://mytracks.appspot.com\'>My Tracks</a> on Android.</string>
|
||||
|
||||
<!-- Text and links when uploading to Google My Maps -->
|
||||
<string name="my_map_link">Created by <a href=\'http://mytracks.appspot.com\'>My Tracks</a> on Android.</string>
|
||||
<string name="new_map_title">Uusi kartta</string>
|
||||
|
||||
<!-- Formatting of track and marker descriptions -->
|
||||
<string name="points">Pisteet</string>
|
||||
<string name="recorded_date">Tallennettu</string>
|
||||
<string name="category">Liikunnan muoto</string>
|
||||
<string name="waypoint_category">Merkinnän tyyppi</string>
|
||||
<string name="part">(Osa %d)</string>
|
||||
|
||||
<!-- Used by the track recording service -->
|
||||
<string name="recording_your_track">Tallennetaan reittiä...</string>
|
||||
<string name="new_track">Reitti %d</string>
|
||||
|
||||
<!-- Common -->
|
||||
<string name="no">Ei</string>
|
||||
<string name="yes">Kyllä</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="error">Virhe</string>
|
||||
<string name="success">Valmis</string>
|
||||
<string name="waypoint">Reittipiste</string>
|
||||
<string name="license">Lisenssi</string>
|
||||
<string name="cancel">Peruuta</string>
|
||||
<string name="close">Sulje</string>
|
||||
<string name="edit">Muokkaa</string>
|
||||
<string name="save">Tallenna</string>
|
||||
|
||||
<!-- Placemark labels for start and end of track -->
|
||||
<string name="start">(Lähtö)</string>
|
||||
<string name="end">(Maali)</string>
|
||||
|
||||
<!-- TrackList -->
|
||||
<string name="tracklist_show_track">Näytä</string>
|
||||
<string name="tracklist_send_to_mymaps">Lähetä Google My Mapsiin</string>
|
||||
<string name="tracklist_send_to_new_mymap">Lähetä New Google My Mapiin</string>
|
||||
<string name="tracklist_send_to_fusiontables">Lähetä Google Fusion Tablesiin</string>
|
||||
<string name="tracklist_send_to_new_fusiontable">Lähetä New Google Fusion Tablesiin</string>
|
||||
<string name="tracklist_send_to_docs">Lähetä Google Docsiin</string>
|
||||
<string name="tracklist_send_to_google">Lähetä Googleen...</string>
|
||||
<string name="tracklist_delete_track">Poista puhelimesta...</string>
|
||||
<string name="tracklist_edit_track">Muokkaa tietoja...</string>
|
||||
<string name="tracklist_write_to_sd">Kirjoita SD-kortille...</string>
|
||||
<string name="tracklist_save_as_gpx">Tallenna GPX-tiedosto</string>
|
||||
<string name="tracklist_save_as_kml">Tallenna KML-tiedosto</string>
|
||||
<string name="tracklist_save_as_csv">Tallenna CSV-tiedosto</string>
|
||||
<string name="tracklist_save_as_tcx">Tallenna TCX-tiedosto</string>
|
||||
<string name="tracklist_btn_send_all_to_fusiontables">Lähetä Google Fusion Tablesiin</string>
|
||||
<string name="tracklist_btn_send_all_to_mymaps">Lähetä Google My Mapsiin</string>
|
||||
<string name="tracklist_btn_delete_all">Poista kaikki</string>
|
||||
<!-- Export All -->
|
||||
<string name="tracklist_btn_export_all">Vie kaikki</string>
|
||||
<string name="export_done">Vienti tehty</string>
|
||||
<string name="tracklist_pick_one">Valitse reitti. Pitkällä painalluksella lisää vaihtoehtoja.</string>
|
||||
<string name="tracklist_all_tracks">Kaikki reitit:</string>
|
||||
<string name="tracklist_this_track">Tämä reitti</string>
|
||||
<string name="tracklist_share_track">Jaa...</string>
|
||||
<string name="tracklist_share_link">Linkki karttaan</string>
|
||||
<string name="tracklist_share_gpx_file">GPX-tiedosto</string>
|
||||
<string name="tracklist_share_kml_file">KML-tiedosto</string>
|
||||
<string name="tracklist_share_csv_file">CSV-tiedosto</string>
|
||||
<string name="tracklist_share_tcx_file">TCX-tiedosto</string>
|
||||
<string name="tracklist_clear_map">Tyhjennä kartta</string>
|
||||
<!-- Import All -->
|
||||
<string name="tracklist_btn_import_all">Tuo kaikki</string>
|
||||
<!-- Format:
|
||||
$1 : Successful imports
|
||||
$2 : Attempted imports
|
||||
$3 : MyTracks gpx path
|
||||
-->
|
||||
<string name="import_multi_done">Tuotu %1$d GPX-tiedostoa %2$d:sta lähteestä %3$s</string>
|
||||
<string name="import_multi_empty">Lähteestä %s ei löytynyt GPX-tiedostoja. SD-kortti saattaa olla lukukelvoton tai hakemistossa ei ole GPX-tiedostoja.</string>
|
||||
<string name="import_error">Virhe tuotaessa tiedostoa %s</string>
|
||||
<string name="import_title">Tuo My Tracksiin</string>
|
||||
<string name="import_success">%1$d reittiä tuotu.</string>
|
||||
<string name="import_show_track">Näytä reitti</string>
|
||||
|
||||
<!-- Waypoints list -->
|
||||
<string name="waypointslist_btn_delete_all">Poista kaikki merkinnät</string>
|
||||
<string name="waypointslist_this_waypoint">Tämä merkintä</string>
|
||||
<string name="waypointslist_delete_waypoint">Poista</string>
|
||||
<string name="waypointslist_edit_waypoint">Muokkaa tietoja</string>
|
||||
<string name="waypointslist_show_waypoint">Näytä kartalla</string>
|
||||
<string name="waypointslist_btn_insert_waypoint">Lisää reittipiste</string>
|
||||
<string name="waypointslist_btn_insert_statistics">Lisää tilastot</string>
|
||||
<string name="waypointslist_pick_one">Valitse merkintä. Pitkä painallus tuo esiin lisää vaihtoehtoja.</string>
|
||||
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">Reitin tiedot</string>
|
||||
<string name="trackdetails_name">Reitin nimi</string>
|
||||
<string name="trackdetails_description">Reitin kuvaus</string>
|
||||
<string name="trackdetails_category">Liikunnan muoto (esim. hölkkä, pyöräily, juoksu...)</string>
|
||||
|
||||
<!-- MyTracks Waypoint Details -->
|
||||
<string name="waypointdetails_title">Merkinnän tiedot</string>
|
||||
<string name="waypointdetails_name">Merkinnän nimi</string>
|
||||
<string name="waypointdetails_description">Merkinnän kuvaus</string>
|
||||
<string name="waypointdetails_category">Merkinnän tyyppi (esim. rakennus, kuoppa, nähtävyys...)</string>
|
||||
|
||||
<!-- MyTracks Settings -->
|
||||
<string name="mytracks_settings">My Tracks Asetukset</string>
|
||||
<string name="settings_display">Näyttö</string>
|
||||
<string name="settings_recording">Tallennus</string>
|
||||
<string name="settings_sharing">Jakaminen</string>
|
||||
|
||||
<string name="settings_not_available_summary">Ei tuettu tässä Android-versiossa</string>
|
||||
<string name="settings_not_while_recording">Ei saatavilla reittiä tallennettaessa.</string>
|
||||
|
||||
<string name="settings_announcement_frequency">Äänimerkki</string>
|
||||
<string name="settings_announcement_frequency_summary">Äänimerkkien aikaväli</string>
|
||||
|
||||
<string name="settings_min_recording_distance">Lyhyin piste-etäisyys</string>
|
||||
<string name="settings_min_recording_distance_summary">Lyhyin sallittu reitintallennuksessa käytetty etäisyys kahden pisteen välillä</string>
|
||||
|
||||
<string name="settings_max_recording_distance">Pisin piste-etäisyys</string>
|
||||
<string name="settings_max_recording_distance_summary">Jos edeltävä piste on valittua etäisyyttä pidemmällä reitti jaetaan</string>
|
||||
|
||||
<string name="settings_min_recording_interval">Lyhyin aika</string>
|
||||
<string name="settings_min_recording_interval_summary">Lyhyin aikaintervalli kahden tallennetun pisteen välillä</string>
|
||||
|
||||
<string name="settings_min_required_accuracy">Sallittu tarkkuus</string>
|
||||
<string name="settings_min_required_accuracy_summary">Reitin tallennus pysäytetään, jos tarkkuus on tätä pienempi</string>
|
||||
|
||||
<string name="settings_metric_units">Käytä metrijärjestelmää</string>
|
||||
<string name="settings_metric_units_summary_on">Kaikki etäisyydet näytetään metrijärjestelmässä</string>
|
||||
<string name="settings_metric_units_summary_off">Kaikki etäisyydet näytetään U.S yksiköitä käyttäen</string>
|
||||
|
||||
<string name="settings_map_public">Aseta kartat julkisiksi</string>
|
||||
<string name="settings_map_public_summary_on">Lähetetyt kartat näkyvät kaikille osoitteessa maps.google.com</string>
|
||||
<string name="settings_map_public_summary_off">Lähetettyjä karttoja ei näytetä julkisesti osoitteessa maps.google.com</string>
|
||||
|
||||
<string name="settings_report_speed_or_pace">Näytä nopeus</string>
|
||||
<string name="settings_report_speed_or_pace_summary_on">Nopeus näytetään</string>
|
||||
<string name="settings_report_speed_or_pace_summary_off">Tahti näytetään</string>
|
||||
|
||||
<string name="settings_share_url_only">Jaa vain URL</string>
|
||||
<string name="settings_share_url_only_summary_on">Ainoastaan kartan URL jaetaan</string>
|
||||
<string name="settings_share_url_only_summary_off">Myös reitin sisältö ja tiedot jaetaan</string>
|
||||
|
||||
<string name="settings_split_frequency">Reitin jaotus</string>
|
||||
<string name="settings_split_frequency_summary">Etäisyys tai aika jolloin reitti jaetaan osiin</string>
|
||||
|
||||
<string name="settings_auto_resume_track_timeout">Reitin jatkaminen</string>
|
||||
<string name="settings_auto_resume_track_timeout_summary">Aika jonka sisällä tallennettavaa reittiä jatketaan, jos puhelin käynnitetään uudelleen.</string>
|
||||
|
||||
<string name="settings_timestamp_track_name">Aikamerkintä nimenä</string>
|
||||
<string name="settings_timestamp_track_name_summary_on">Oletusnimenä reitille käytetään aloituspäivämäärää ja aikaa</string>
|
||||
<string name="settings_timestamp_track_name_summary_off">Oletusnimenä käytetään kasvavaa numerointia.</string>
|
||||
|
||||
<string name="settings_reset">Palauta oletusasetukset</string>
|
||||
<string name="settings_reset_summary">Palauta kaikki oletusasetukset</string>
|
||||
<string name="settings_reset_dialog_message">Kaikki asetuksesi poistetaan ja palautetaan oletusarvoisiksi. Tallennetut reitit säilytetään. Oletko varma?</string>
|
||||
<string name="settings_reset_done">Oletusasetukset palautettu.</string>
|
||||
|
||||
<string name="pace_label">Tahti</string>
|
||||
|
||||
<string name="eclair_required">Tuettuna vain Android 2.0 tai uudemmassa</string>
|
||||
<string name="settings_sensor_type">Sensorin tyyppi</string>
|
||||
<string name="settings_sensor_type_summary">Sensorin tyyppi johon yhdistetään</string>
|
||||
<string name="settings_heart_rate_ant_sensor_id">Resetoi ANT sykemittarin paritus</string>
|
||||
<string name="settings_power_ant_sensor_id">Resetoi ANT tehomittarin paritus</string>
|
||||
<string name="settings_srm_bridge_ant_sensor_id">Resetoi ANT SRM sillan paritus</string>
|
||||
<string name="settings_ant_not_paired">ANT sensori ei paritettu</string>
|
||||
<string name="settings_ant_paired">ANT sensori paritettu: %d</string>
|
||||
<string name="bluetooth_sensor_title">Bluetooth sensori</string>
|
||||
<string name="bluetooth_sensor_summary">Bluetooth-sensori johon yhdistetään</string>
|
||||
<string name="settings_modular_stats_display_title">Modular Stats Display</string>
|
||||
|
||||
<!-- Backups -->
|
||||
<string name="settings_backup">Varmuuskopioi (BETA)</string>
|
||||
<string name="settings_sd_backup">Varmuuskopioi SD-kortille</string>
|
||||
<string name="settings_backup_to_sd">Varmuuskopioi</string>
|
||||
<string name="settings_backup_to_sd_summary">Tallenna täydellinen kopio reiteistä ja asetuksista SD-kortille</string>
|
||||
<string name="settings_restore_from_sd">Palauta</string>
|
||||
<string name="settings_restore_from_sd_summary">Palauta kaikki reitit ja asetukset SD-kortilta</string>
|
||||
|
||||
<string name="restore_overwrites_warning">Palautus SD-kortilta ylikirjoittaa kaikki nykyiset reitit ja asetukset. Jatketaanko?</string>
|
||||
<string name="select_backup_to_restore">Valitse palautettava varmuuskopio</string>
|
||||
<string name="no_backups">Varmuuskopioita ei löytynyt.</string>
|
||||
<string name="backup_write_progress_message">Luodaan varmuuskopiota. Odota...</string>
|
||||
<string name="backup_import_progress_message">Luetaan varmuuskopiota SD-kortilta. Odota...</string>
|
||||
|
||||
<!-- MyTracksSky -->
|
||||
<string name="mytracks_sky">GPS-satelliitit</string>
|
||||
|
||||
<!-- My Maps -->
|
||||
<string name="select_map_message">Valitse kartta tililtäsi:</string>
|
||||
<string name="create_new_map">Luo uusi kartta...</string>
|
||||
<string name="map_list_title">Lähetä Google My Mapsiin</string>
|
||||
<string name="maps_list_loading">Ladataan karttoja...</string>
|
||||
<string name="maps_list_failed">Karttoja ei voitu ladata!</string>
|
||||
<string name="open_map">Valitse tämä kartta</string>
|
||||
<string name="edit_map_details">Muokkaa kartan tietoja</string>
|
||||
<string name="share_track">Jaa reitti</string>
|
||||
<string name="delete_map">Poista kartta tililtä</string>
|
||||
<string name="map_title">Kartan otsikko:</string>
|
||||
<string name="map_description">Kartan kuvaus:</string>
|
||||
<string name="map_searchable_edit">Näytä kartta ja sen sisältö hakutuloksissa</string>
|
||||
<string name="map_not_searchable_edit">Älä näytä karttaa tai sen sisältöä hakutuloksissa. Tiedot näkyvät suoralla URL-linkillä</string>
|
||||
<string name="map_searchable">Tämä kartta ja sen sisältö näkyy hakutuloksissa</string>
|
||||
<string name="map_not_searchable">Kartta tai sen sisältö ei näy hakutuloksissa. Tiedot näkyvät muille kuitenkin suoralla URL-linkillä</string>
|
||||
|
||||
<!-- Sharing -->
|
||||
<string name="share_map">Jaa kartta</string>
|
||||
<string name="share_map_subject">Haluaisin jakaa kartan kanssasi</string>
|
||||
<string name="share_map_body_format">Saattaisit olla kiinnostunut tästä reitistä:
|
||||
|
||||
%s</string>
|
||||
<string name="send_track_subject">Haluaisin jakaa reitin kanssasi</string>
|
||||
<string name="send_track_body_format">Saattaisit olla kiinnostunut tästä reitistä.
|
||||
|
||||
Käytä Google Earthia tai jotain muuta karttaohjelmistoa kartan katsomiseen.</string>
|
||||
|
||||
<!-- Visibility -->
|
||||
<string name="public_map">Julkinen</string>
|
||||
<string name="unlisted_map">Ei listattu</string>
|
||||
<string name="mapslist_no_maps_available">Ei karttoja saatavilla.</string>
|
||||
|
||||
<!-- Statistics View -->
|
||||
<!-- Average Moving -->
|
||||
<string name="average_moving_speed_label">Keskinopeus (liikuttaessa)</string>
|
||||
<string name="average_moving_pace_label">Tahti (liikuttaessa)</string>
|
||||
|
||||
<!-- Average -->
|
||||
<string name="average_speed_label">Keskinopeus</string>
|
||||
<string name="average_pace_label">Tahti</string>
|
||||
|
||||
<string name="elevation_chart_name">Korkeuskaavio</string>
|
||||
<string name="elevation_gain_label">Nousu</string>
|
||||
<string name="elevation_label">Korkeus</string>
|
||||
<string name="latitude_label">Leveysaste</string>
|
||||
<string name="longitude_label">Pituuspiiri</string>
|
||||
|
||||
<!-- Min -->
|
||||
<string name="min_elevation_label">Min Korkeus</string>
|
||||
<string name="min_grade_label">Min Kaltevuus</string>
|
||||
<string name="min_pace_label">Min Tahti</string>
|
||||
|
||||
<!-- Max -->
|
||||
<string name="max_elevation_label">Max Korkeus</string>
|
||||
<string name="max_grade_label">Max Kaltevuus</string>
|
||||
<string name="max_speed_label">Max Nopeus</string>
|
||||
|
||||
<string name="loading_track">Ladataan reittiä...</string>
|
||||
|
||||
<!-- Chart Settings -->
|
||||
<string name="chart_settings">Kaavion asetukset</string>
|
||||
<!-- X Axis -->
|
||||
<string name="x_axis">X-akseli</string>
|
||||
<string name="by_distance">Etäisyyden mukaan</string>
|
||||
<string name="by_time">Ajan mukaan</string>
|
||||
|
||||
<!-- Y Axis -->
|
||||
<string name="y_axis">Y-akseli</string>
|
||||
|
||||
<!-- Units -->
|
||||
<!-- Time -->
|
||||
<string name="hour">tunti</string>
|
||||
<string name="hours">tuntia</string>
|
||||
<string name="hr">h</string>
|
||||
<string name="min">min</string>
|
||||
<string name="minute">minuutti</string>
|
||||
<string name="minutes">minuuttia</string>
|
||||
<string name="second">sekunti</string>
|
||||
<string name="seconds">sekuntia</string>
|
||||
<string name="milliseconds">ms</string>
|
||||
|
||||
<!-- Distance -->
|
||||
<string name="meter">m</string>
|
||||
<string name="kilometer">km</string>
|
||||
<string name="kilometers_long">kilometriä</string>
|
||||
<string name="feet">ft</string>
|
||||
<string name="mile">mi</string>
|
||||
<string name="miles_long">mailia</string>
|
||||
|
||||
<!-- Speed and Pace -->
|
||||
<string name="kilometer_per_hour">km/h</string>
|
||||
<string name="kilometer_per_hour_long">kilometriä tunnissa</string>
|
||||
<string name="min_per_kilometer">min/km</string>
|
||||
<string name="per_kilometer">per kilometri</string>
|
||||
<string name="mile_per_hour">mi/h</string>
|
||||
<string name="mile_per_hour_long">mailia tunnissa</string>
|
||||
<string name="min_per_mile">min/mi</string>
|
||||
<string name="per_mile">per maili</string>
|
||||
|
||||
<!-- Sensors -->
|
||||
<string name="watts">W</string>
|
||||
|
||||
<string name="revolutions_per_minute">rpm</string>
|
||||
<string name="bpm">bpm</string>
|
||||
|
||||
<!-- Stats Labels -->
|
||||
<string name="moving_time_label">Liikkumisaika</string>
|
||||
<string name="total_time_label">Kokonaisaika</string>
|
||||
<string name="time_label">Aika</string>
|
||||
<string name="sd_unavail">Muistikortti ei ole käytettävissä</string>
|
||||
<string name="speed">Nopeus</string>
|
||||
<string name="start_trip">Sinun pitää ensin aloittaa matka.</string>
|
||||
<string name="statistics">Tilastot</string>
|
||||
<string name="total_distance_label">Kokonaismatka</string>
|
||||
<string name="distance_label">Matka</string>
|
||||
<string name="power">Teho</string>
|
||||
<string name="cadence">Kadenssi</string>
|
||||
<string name="heart_rate">Syke</string>
|
||||
<string name="max_heart_rate">Maksimisyke</string>
|
||||
<string name="unknown">-</string>
|
||||
<string name="waiting">Odotetaan...</string>
|
||||
|
||||
<!-- End User License Agreement -->
|
||||
<string name="eula_title">End User License Agreement</string>
|
||||
<string name="accept">Hyväksy</string>
|
||||
<string name="decline">Hylkää</string>
|
||||
|
||||
<!-- About -->
|
||||
<string name="about">Tietoja</string>
|
||||
<string name="help">Apua</string>
|
||||
<string name="about_team">Tiimi:</string>
|
||||
<string name="about_version">Version:</string>
|
||||
<string name="about_support">Tuki:</string>
|
||||
<string name="about_privacy">Yksityisyys:</string>
|
||||
|
||||
<!-- Send to Google -->
|
||||
<string name="sendtogoogle_title">Lähetä...</string>
|
||||
<string name="sendtogoogle_google_fusiontables">Google Fusion Tables</string>
|
||||
<string name="sendtogoogle_google_mymaps">Google My Maps</string>
|
||||
<string name="sendtogoogle_google_docs">Google Docs</string>
|
||||
<string name="sendtogoogle_send_now">Lähetä</string>
|
||||
<string name="sendtogoogle_create_new_map">Luo uusi kartta</string>
|
||||
<string name="sendtogoogle_pick_existing_map">Valitse kartta</string>
|
||||
<string name="sendtogoogle_send_stats">Lähetä reitin statistiikka</string>
|
||||
<string name="sendtogoogle_send_stats_and_points">Lähetä reitin statistiikka ja pisteet</string>
|
||||
|
||||
<!-- Getting the account to upload to. -->
|
||||
<string name="no_account_found_title">Tiliä ei löytynyt</string>
|
||||
<string name="no_account_found">Tiliä johon reitin voisi lähettää ei löytynyt.</string>
|
||||
<string name="choose_account_title">Valitse tili</string>
|
||||
|
||||
<!-- SD card -->
|
||||
<string name="io_no_external_storage_found">Ulkoista tallennusmediaa ei löytynyt. Varmista että SD-kortti on kytketty eikä puhelinta ole liitetty tietokoneeseen.</string>
|
||||
<string name="io_write_failed">Kirjoitusvirhe.</string>
|
||||
<string name="io_read_failed">Lukuvirhe.</string>
|
||||
<string name="io_create_dir_failed">Hakemistoa ei voitu luoda SD-kortille.</string>
|
||||
<string name="io_write_finished">SD-kortille kirjoitus valmis.</string>
|
||||
<string name="io_read_finished">SD-kortin luku valmis.</string>
|
||||
|
||||
<!-- VersionChecker -->
|
||||
<string name="version_check_title">Tarkista päivitykset</string>
|
||||
<string name="version_check_upgrade_button">Päivitä</string>
|
||||
<string name="version_check_continue_button">Ohita päivitys</string>
|
||||
<string name="upgrade_required">Käytössäsi oleva versio ohjelmasta %1$s saattaa lakata toimimasta eikä ole enää tuettu. Päivitä jatkaaksesi %1$s käyttöä.</string>
|
||||
<string name="upgrade_recommended">Käytössäsi oleva versio ohjelmasta %1$s saattaa lakata toimimasta. Voit päivittää sen nyt tai jatkaa käyttöä omalla riskillä. Tietyt ominaisuudet, kuten synkronointi serverin kanssa, ei välttämättä toimi ennen päivitystä.</string>
|
||||
<string name="upgrade_available">%1$s uusi versio saatavilla. Voit jatkaa nykyisen version käyttöä tai päivitää uuteen versioon.</string>
|
||||
|
||||
<!-- Welcome -->
|
||||
<string name="welcome">Tervetuloa</string>
|
||||
<string name="welcome_read_later">Ok</string>
|
||||
<string name="welcome_about">Tietoa My Tracksista</string>
|
||||
|
||||
<!-- Announcement -->
|
||||
<string name="announce_no_distance">My Tracks ei etäisyyttä</string>
|
||||
<!-- Format:
|
||||
$1 : Distance label
|
||||
$2 : Distance value (5)
|
||||
$3 : Distance units (mi, km)
|
||||
$4 : Time description (10 minutes 5 seconds)
|
||||
$5 : Speed value (5.6) : Pace value (5 minutes 6 seconds)
|
||||
$6 : Speed units (mph) : Pace units (per mile)
|
||||
-->
|
||||
<string name="announce_template">My Tracks %1$s %2$.2f %3$s ajassa %4$s nopeudella %5$s %6$s</string>
|
||||
|
||||
<!-- Check Units -->
|
||||
<string name="check_units_title">Huomautus mittayksiköistä</string>
|
||||
<string name="check_units_message">Oletuksena käytössä on metrijärjestelmä. Haluatko muuttaa asetuksen?</string>
|
||||
|
||||
<!-- Fake preference keys - never saved, but show options in the preferences screen -->
|
||||
<string name="method_bluetooth">Bluetooth</string>
|
||||
<string name="bluetooth_options">Bluetooth asetukset</string>
|
||||
<string name="bluetooth_pairing">Laiteparit</string>
|
||||
<string name="bluetooth_pairing_summary">Avaa Androidin bluetooth-asetukset luodaksesi laitepareja</string>
|
||||
<string name="sensor_bluetooth_options_key">bluetoothSensorsEnabled</string>
|
||||
<string name="ant_options">ANT asetukset</string>
|
||||
<string name="sensor_options">Sensorien asetukset</string>
|
||||
|
||||
<!-- Bluetooth Sensor -->
|
||||
<string name="bluetooth_connected">Yhdistetty %s</string>
|
||||
<string name="bluetooth_connecting">Yhdistetään bluetooth sensoria ...</string>
|
||||
<string name="bluetooth_not_connected">Bluetooth sensoria ei ole yhdistetty</string>
|
||||
|
||||
<!-- Sensor State -->
|
||||
<string name="sensor_data_time">Sensorin data-aika</string>
|
||||
<string name="power_meter_enabled">Tehomittari käytössä</string>
|
||||
<string name="heart_rate_monitor_enabled">Sykemittari käytössä</string>
|
||||
<string name="no_sensor_manager">Ei sensorihallintaa</string>
|
||||
<string name="enabled">Käytössä</string>
|
||||
<string name="connecting">Yhdistetään</string>
|
||||
<string name="connected">Yhdistetty</string>
|
||||
<string name="disconnected">Katkaistu</string>
|
||||
<string name="no_sensor_service">Ei sensoripalvelua</string>
|
||||
<string name="searching">Etsitään</string>
|
||||
<string name="sending">Lähetetään</string>
|
||||
|
||||
<string name="no_sensor_option">Ei sensoria</string>
|
||||
<string name="ant_sensor_option">ANT+ -sensori</string>
|
||||
<string name="ant_bridge_sensor_option">SRM ANT+ -silta</string>
|
||||
<string name="polar_bt_sensor_option">Polar bluetooth</string>
|
||||
<string name="zephyr_bt_sensor_option">Zephyr bluetooth</string>
|
||||
|
||||
<!-- Manifest description (not seen inside the app) -->
|
||||
<string name="notification_permission_label">vastaanota huomautuksia reitin tallentamisesta</string>
|
||||
<string name="read_tracks_permission_label">lue tallennettua reittidataa</string>
|
||||
<string name="write_tracks_permission_label">kirjoita tallennettua reittidataa, aloita/pysäytä reitin tallennus</string>
|
||||
<string name="notification_permission_description">Huomauta kun reitin tallennus aloitetaan tai pysäytetään..</string>
|
||||
<string name="read_tracks_permission_description">Mahdollista reittidatan lukeminen, kuten reittipisteet, merkinnät jne.</string>
|
||||
<string name="write_tracks_permission_description">Mahdollista reittidatan kirjoittaminen, kuten tallennuksen aloittaminen, merkintöjen lisääminen jne.</string>
|
||||
</resources>
|
||||
@@ -291,11 +291,4 @@ limitations under the License.
|
||||
<item>point de passage</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>Aucun</item>
|
||||
<item>Capteur ANT+</item>
|
||||
<item>Pont SRM ANT+</item>
|
||||
<item>Bluetooth Zephyr</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -397,6 +397,13 @@ limitations under the License.
|
||||
<string name="searching">Recherche</string>
|
||||
<string name="sending">Envoi</string>
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">Aucun</string>
|
||||
<string name="ant_sensor_option">Capteur ANT+</string>
|
||||
<string name="ant_bridge_sensor_option">Pont SRM ANT+</string>
|
||||
<string name="polar_bt_sensor_option">Bluetooth Polar</string>
|
||||
<string name="zephyr_bt_sensor_option">Bluetooth Zephyr</string>
|
||||
|
||||
<!-- Manifest description (not seen inside the app) -->
|
||||
<string name="notification_permission_label">notifications lors de l\'enregistrement de parcours</string>
|
||||
<string name="read_tracks_permission_label">lecture des parcours enregistrés</string>
|
||||
|
||||
@@ -272,11 +272,4 @@ limitations under the License.
|
||||
<item>ウェイポイント</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>なし</item>
|
||||
<item>ANT+ センサー</item>
|
||||
<item>SRM ANT+ ブリッジ</item>
|
||||
<item>Zephyr Bluetooth</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -159,8 +159,8 @@ limitations under the License.
|
||||
$2 : Attempted imports
|
||||
$3 : MyTracks gpx path
|
||||
-->
|
||||
<string name="import_done">%3$s からGPXファイル %2$d件のうち %1$d件をインポートしました</string>
|
||||
<string name="import_empty">%s ではGPXファイルがありません.SDカードを読み込めないかディレクトリにGPXファイルが無いかも知れません.</string>
|
||||
<string name="import_multi_done">%3$s からGPXファイル %2$d件のうち %1$d件をインポートしました</string>
|
||||
<string name="import_multi_empty">%s ではGPXファイルがありません.SDカードを読み込めないかディレクトリにGPXファイルが無いかも知れません.</string>
|
||||
<string name="import_error">ファイル %s のインポートエラー</string>
|
||||
|
||||
<!-- Waypoints list -->
|
||||
@@ -463,6 +463,11 @@ limitations under the License.
|
||||
<string name="searching">検索中</string>
|
||||
<string name="sending">送信中</string>
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">なし</string>
|
||||
<string name="ant_sensor_option">ANT+ センサー</string>
|
||||
<string name="ant_bridge_sensor_option">SRM ANT+ ブリッジ</string>
|
||||
|
||||
<!-- Manifest description (not seen inside the app) -->
|
||||
<string name="notification_permission_label">トラック記録通知受信</string>
|
||||
<string name="read_tracks_permission_label">トラック読み込み</string>
|
||||
|
||||
@@ -272,11 +272,4 @@ limitations under the License.
|
||||
<item>путевая точка</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>Нет</item>
|
||||
<item>ANT+ Sensors</item>
|
||||
<item>SRM ANT+ Bridge</item>
|
||||
<item>Zephyr Bluetooth</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -162,8 +162,8 @@ limitations under the License.
|
||||
$2 : Attempted imports
|
||||
$3 : MyTracks gpx path
|
||||
-->
|
||||
<string name="import_done">Импортировано %1$d из %2$d GPX файлов с %3$s</string>
|
||||
<string name="import_empty">GPX файлы не найденны в %s. Возможно не читается SD-карта или каталог не содержит GPX файлы.</string>
|
||||
<string name="import_multi_done">Импортировано %1$d из %2$d GPX файлов с %3$s</string>
|
||||
<string name="import_multi_empty">GPX файлы не найденны в %s. Возможно не читается SD-карта или каталог не содержит GPX файлы.</string>
|
||||
<string name="import_error">Ошибка импорта файла %s</string>
|
||||
|
||||
<!-- Waypoints list -->
|
||||
@@ -490,6 +490,11 @@ limitations under the License.
|
||||
<string name="searching">Поиск</string>
|
||||
<string name="sending">Отправка</string>
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">Нет</string>
|
||||
<string name="ant_sensor_option">ANT+ Датчик</string>
|
||||
<string name="ant_bridge_sensor_option">SRM ANT+ Bridge</string>
|
||||
|
||||
<!-- Manifest description (not seen inside the app) -->
|
||||
<string name="notification_permission_label">получать уведомления о записи трека</string>
|
||||
<string name="read_tracks_permission_label">чтение записанных данных трека</string>
|
||||
|
||||
@@ -170,6 +170,11 @@ limitations under the License.
|
||||
<item>轮滑</item>
|
||||
<item>滑板</item>
|
||||
|
||||
<item>滚轮滑雪 (传统)</item>
|
||||
<item>滚轮滑雪 (滑板)</item>
|
||||
<item>越野滑雪 (传统)</item>
|
||||
<item>越野滑雪 (滑板)</item>
|
||||
|
||||
<item>雪攀</item>
|
||||
<item>滑雪</item>
|
||||
<item>雪板</item>
|
||||
|
||||
@@ -29,19 +29,23 @@ limitations under the License.
|
||||
<string name="choose_track_message">请选择要查看的轨迹</string>
|
||||
<string name="current_track">当前轨迹</string>
|
||||
<string name="current_segment">上一段轨迹</string>
|
||||
<string name="sensor_state">感应器状态</string>
|
||||
<string name="aggregated_stats">累积统计</string>
|
||||
|
||||
<!-- Error messages -->
|
||||
<string name="error_no_location_manager">此设备上没有位置管理器!</string>
|
||||
<string name="error_no_gps_location_provider">此设备上没有 GPS 定位装置.</string>
|
||||
<string name="error_sending_to_fusiontables">发送你的轨迹到 Google Fusion Tables 时发生错误. 请稍后重试.</string>
|
||||
<string name="error_sending_to_docs">发送你的轨迹到 Google Docs 时发生错误. 请稍后重试.</string>
|
||||
<string name="error_sending_to_mymap">发送轨迹到 Google My Map 时发生错误.</string>
|
||||
<string name="error_sending_to_fusiontables">发送轨迹到 Google Fusion Tables 时发生错误. 请稍后重试.</string>
|
||||
<string name="error_sending_to_docs">发送轨迹到 Google Docs 时发生错误. 请稍后重试.</string>
|
||||
<string name="error_please_try_again_later">请稍后再试.</string>
|
||||
<string name="error_unable_to_start_recording">无法开始记录. 请重试.</string>
|
||||
<string name="error_unable_to_stop_recording">无法停止记录. 请重试.</string>
|
||||
<string name="error_unable_to_read_file">无法读取文件.</string>
|
||||
<string name="error_invalid_gpx_format">文件不是有效的 GPX 格式.</string>
|
||||
<string name="error_generic">发生错误. 请重试.</string>
|
||||
<string name="error_track_does_not_exist">轨迹不存在.</string>
|
||||
<string name="error_operation_cancelled">操作已被取消.</string>
|
||||
<string name="error_out_of_memory">文件太大 (必须小于 500 KB). 中止操作.</string>
|
||||
<string name="error_unable_to_insert_marker">无法插入标记. 定位尚未完成.</string>
|
||||
|
||||
@@ -49,15 +53,18 @@ limitations under the License.
|
||||
<string name="wait_for_fix">等待更准确的 GPS 定位. 请确定可以看见天空.</string>
|
||||
<string name="status_now_recording">现在开始记录新的轨迹.</string>
|
||||
<string name="status_stopped_recording">停止记录你的轨迹.</string>
|
||||
<string name="status_new_mymap_has_been_created">已在 maps.google.com 创建了新的 Google My Map.</string>
|
||||
<string name="status_new_fusiontable_has_been_created">已在 google.com/fusiontables 创建新 Google Fusion Table.</string>
|
||||
<string name="status_tracks_have_been_uploaded">你的轨迹已经发送到 maps.google.com.</string>
|
||||
<string name="status_tracks_have_been_uploaded_to_new_doc">你的轨迹已经作为新的电子表格发送到 docs.google.com.</string>
|
||||
<string name="status_tracks_have_been_uploaded_to_docs">你的轨迹已经发送到 docs.google.com.</string>
|
||||
<string name="status_mymap_info">可能需要等待几分钟才能看见新的轨迹.</string>
|
||||
<string name="status_enable_gps">请点击这里进入\'安全和位置设置\'并勾选上\'启用 GPS 卫星\'. 然后用后退键返回.</string>
|
||||
<string name="status_approximate_location">注意: 当前显示的位置是根据无线信号和无线网络计算的近似位置.</string>
|
||||
<string name="status_no_location">目前无法定位. 请启用更多的位置来源 (在\'安全和位置设置\'中) 并确认天空是可见的. 再重试.</string>
|
||||
<string name="status_waypoint_inserted">插入了一个路点标记.</string>
|
||||
<string name="status_statistics_inserted">插入了一个统计标记.</string>
|
||||
<string name="status_track_upload_status">上传状态:</string>
|
||||
|
||||
<!-- Progress dialog -->
|
||||
<string name="progress_title">请稍候...</string>
|
||||
@@ -69,6 +76,9 @@ limitations under the License.
|
||||
<string name="progress_message_sending_docs">发送轨迹到 Google Docs 中...</string>
|
||||
<string name="progress_message_sending_fusiontables">发送轨迹到 Google Fusion Tables 中...</string>
|
||||
<string name="progress_message_creating_fusiontable">创建新的 Fusion Table 中...</string>
|
||||
<string name="progress_message_creating_map">创建新的 My Map...</string>
|
||||
<string name="progress_message_sending_fusiontables">发送轨迹到 Fusion Tables...</string>
|
||||
<string name="progress_message_creating_fusiontable">创建新的 Fusion table...</string>
|
||||
<string name="import_progress_message">导入 GPS 轨迹中. 请稍候.</string>
|
||||
<string name="write_progress_message">写入文件到 SD 卡中. 请稍候.</string>
|
||||
<string name="progress_message_updating_track">更新轨迹统计信息中...</string>
|
||||
@@ -79,12 +89,16 @@ limitations under the License.
|
||||
<string name="track_will_be_permanently_deleted">选定轨迹和它相关的标记都将被从本机彻底删除.</string>
|
||||
<string name="marker_will_be_permanently_deleted">选定标记将被从本机删除.</string>
|
||||
|
||||
<!-- Text and links when uploading to Google Fusion Tables -->
|
||||
<string name="new_map_description">由 Android 平台的 My Tracks 创建.</string>
|
||||
<string name="fusiontable_link">由 Android 平台的 <a href=\'http://mytracks.appspot.com\'>My Tracks</a> 创建.</string>
|
||||
|
||||
<!-- Text and links when uploading to Google My Maps -->
|
||||
<string name="new_map_description">由 Android 上的 My Tracks 生成.</string>
|
||||
<string name="fusiontable_link">由 Android 上的 <a href=\'http://mytracks.appspot.com\'>My Tracks</a> 生成.</string>
|
||||
<string name="fusiontable_link">由 Android 上的 <a href=\'http://mytracks.appspot.com\'>My Tracks</a> 创建.</string>
|
||||
<string name="new_map_title">新地图</string>
|
||||
|
||||
<!-- Formatting of track and marker descriptions -->
|
||||
<string name="points">点数</string>
|
||||
<string name="points">路点</string>
|
||||
<string name="recorded_date">记录日期</string>
|
||||
<string name="category">活动类型</string>
|
||||
<string name="waypoint_category">标记类型</string>
|
||||
@@ -101,6 +115,7 @@ limitations under the License.
|
||||
<string name="error">错误</string>
|
||||
<string name="success">成功</string>
|
||||
<string name="waypoint">路点</string>
|
||||
<string name="license">授权</string>
|
||||
<string name="cancel">取消</string>
|
||||
<string name="close">关闭</string>
|
||||
<string name="edit">编辑</string>
|
||||
@@ -112,8 +127,10 @@ limitations under the License.
|
||||
|
||||
<!-- TrackList -->
|
||||
<string name="tracklist_show_track">显示</string>
|
||||
<string name="tracklist_send_to_mymaps">发送到 Google My Maps</string>
|
||||
<string name="tracklist_send_to_new_mymap">发送到新建的 Google My Map</string>
|
||||
<string name="tracklist_send_to_fusiontables">发送到 Google Fusion Table</string>
|
||||
<string name="tracklist_send_to_new_fusiontable">发送到新建 Google Fusion Table</string>
|
||||
<string name="tracklist_send_to_new_fusiontable">发送到新建的 Google Fusion Table</string>
|
||||
<string name="tracklist_send_to_docs">发送到 Google Docs</string>
|
||||
<string name="tracklist_send_to_google">发送到 Google...</string>
|
||||
<string name="tracklist_delete_track">从手机上删除...</string>
|
||||
@@ -124,6 +141,7 @@ limitations under the License.
|
||||
<string name="tracklist_save_as_csv">保存为 CSV 文件</string>
|
||||
<string name="tracklist_save_as_tcx">保存为 TCX 文件</string>
|
||||
<string name="tracklist_btn_send_all_to_fusiontables">发送到 Google Fusion Tables</string>
|
||||
<string name="tracklist_btn_send_all_to_mymaps">发送到 Google My Maps</string>
|
||||
<string name="tracklist_btn_delete_all">删除所有轨迹</string>
|
||||
<!-- Export All -->
|
||||
<string name="tracklist_btn_export_all">导出所有轨迹</string>
|
||||
@@ -132,11 +150,22 @@ limitations under the License.
|
||||
<string name="tracklist_all_tracks">全部轨迹:</string>
|
||||
<string name="tracklist_this_track">此轨迹</string>
|
||||
<string name="tracklist_share_track">与朋友分享...</string>
|
||||
<string name="tracklist_share_link">访问地图的超链接</string>
|
||||
<string name="tracklist_share_gpx_file">GPX 文件</string>
|
||||
<string name="tracklist_share_kml_file">KML 文件</string>
|
||||
<string name="tracklist_share_csv_file">CSV 文件</string>
|
||||
<string name="tracklist_share_tcx_file">TCX 文件</string>
|
||||
<string name="tracklist_clear_map">清除地图</string>
|
||||
<!-- Import All -->
|
||||
<string name="tracklist_btn_import_all">全部导入</string>
|
||||
<!-- Format:
|
||||
$1 : Successful imports
|
||||
$2 : Attempted imports
|
||||
$3 : MyTracks gpx path
|
||||
-->
|
||||
<string name="import_done">已从 %3$s 导入 %1$d 个 GPX 文件, 共 %2$d 个.</string>
|
||||
<string name="import_empty">在 %s 中未找到 GPX 文件. SD 存储卡不可用或者目录中没有 GPX 文件.</string>
|
||||
<string name="import_error">导入文件 %s 出错.</string>
|
||||
|
||||
<!-- Waypoints list -->
|
||||
<string name="waypointslist_btn_delete_all">删除所有标记</string>
|
||||
@@ -166,10 +195,11 @@ limitations under the License.
|
||||
<string name="settings_recording">记录</string>
|
||||
<string name="settings_sharing">分享</string>
|
||||
|
||||
<string name="settings_not_available_summary">你使用的 Android 版本无法支持</string>
|
||||
<string name="settings_not_available_summary">不支持当前使用的 Android 版本</string>
|
||||
<string name="settings_not_while_recording">在记录轨迹时不可用</string>
|
||||
|
||||
<string name="settings_announcement_frequency">提示频度</string>
|
||||
<string name="settings_announcement_frequency_summary">语音提示的最小时间间隔</string>
|
||||
<string name="settings_announcement_frequency">通知频度</string>
|
||||
<string name="settings_announcement_frequency_summary">语音通知的最小时间间隔</string>
|
||||
|
||||
<string name="settings_min_recording_distance">最小记录间距</string>
|
||||
<string name="settings_min_recording_distance_summary">位置记录的最小间隔距离</string>
|
||||
@@ -205,14 +235,30 @@ limitations under the License.
|
||||
<string name="settings_auto_resume_track_timeout">自动恢复追踪等待时间</string>
|
||||
<string name="settings_auto_resume_track_timeout_summary">手机重启后自动继续上次轨迹记录的最大间隔时间</string>
|
||||
|
||||
<string name="settings_timestamp_track_name">使用时间作为轨迹名称</string>
|
||||
<string name="settings_timestamp_track_name_summary_on">使用轨迹记录的开始时间作为默认名称</string>
|
||||
<string name="settings_timestamp_track_name_summary_off">轨迹使用自动递增的数字进行命名.</string>
|
||||
|
||||
<string name="settings_reset">恢复默认值</string>
|
||||
<string name="settings_reset_summary">将所有设置恢复到默认值</string>
|
||||
<string name="settings_reset_dialog_message">你的所有设置都将恢复到默认值. 已保存的轨迹不会丢失. 确定要继续吗?</string>
|
||||
<string name="settings_reset_done">所有设置已恢复到默认值.</string>
|
||||
|
||||
<string name="pace_label">节奏</string>
|
||||
|
||||
<string name="eclair_required">只在 Android 2.0 及以上版本支持</string>
|
||||
<string name="settings_sensor_type">感应器类型</string>
|
||||
<string name="settings_sensor_type_summary">要连接到的感应器类型</string>
|
||||
<string name="settings_heart_rate_ant_sensor_id">清除 ANT 心率计的设备关联</string>
|
||||
<string name="settings_power_ant_sensor_id">清除 ANT 能量感应器的设备关联</string>
|
||||
<string name="settings_srm_bridge_ant_sensor_id">清除 ANT SRM 桥接感应器的设备关联</string>
|
||||
<string name="settings_ant_not_paired">ANT 感应器未关联</string>
|
||||
<string name="settings_ant_paired">ANT 感应器已关联到: %d</string>
|
||||
<string name="bluetooth_sensor_title">蓝牙感应器</string>
|
||||
<string name="bluetooth_sensor_summary">要连接到的蓝牙感应器</string>
|
||||
<string name="bluetooth_sensor_summary">想要连接的蓝牙感应器</string>
|
||||
<string name="settings_modular_stats_display_title">模块化状态显示</string>
|
||||
|
||||
<!-- Backups -->
|
||||
<string name="settings_backup">备份 (测试版)</string>
|
||||
<string name="settings_sd_backup">SD 存储卡备份</string>
|
||||
<string name="settings_backup_to_sd">立即备份</string>
|
||||
@@ -220,7 +266,6 @@ limitations under the License.
|
||||
<string name="settings_restore_from_sd">立即恢复</string>
|
||||
<string name="settings_restore_from_sd_summary">从 SD 存储卡恢复所有轨迹和设置</string>
|
||||
|
||||
<!-- Backups -->
|
||||
<string name="restore_overwrites_warning">从 SD 存储卡恢复备份数据将覆盖掉你当前的所有轨迹和设置. 确定要继续吗?</string>
|
||||
<string name="select_backup_to_restore">请选择要恢复的备份文件</string>
|
||||
<string name="no_backups">没有找到备份文件.</string>
|
||||
@@ -230,7 +275,25 @@ limitations under the License.
|
||||
<!-- MyTracksSky -->
|
||||
<string name="mytracks_sky">GPS 卫星</string>
|
||||
|
||||
<!-- My Maps -->
|
||||
<string name="select_map_message">从你的帐号中选择一个地图:</string>
|
||||
<string name="create_new_map">创建新地图...</string>
|
||||
<string name="map_list_title">发送到 Google My Maps</string>
|
||||
<string name="maps_list_loading">载入地图中...</string>
|
||||
<string name="maps_list_failed">现在无法载入你的地图!</string>
|
||||
<string name="open_map">选择此地图</string>
|
||||
<string name="edit_map_details">编辑地图详细信息</string>
|
||||
<string name="share_track">分享轨迹</string>
|
||||
<string name="delete_map">从你的帐号删除地图</string>
|
||||
<string name="map_title">地图标题:</string>
|
||||
<string name="map_description">地图描述:</string>
|
||||
<string name="map_searchable_edit">让此地图和它的内容出现在搜索结果中</string>
|
||||
<string name="map_not_searchable_edit">不要让这个地图的的内容出现在搜索结果中, 但其它用户依然可以通过直接 URL 访问它</string>
|
||||
<string name="map_searchable">此地图和它的内容将在搜索结果中出现</string>
|
||||
<string name="map_not_searchable">此地图和它的内容不会在搜索结果中出现, 但其它用户依然可以通过直接 URL 访问它</string>
|
||||
|
||||
<!-- Sharing -->
|
||||
<string name="share_map">与朋友分享地图</string>
|
||||
<string name="share_map_subject">我想与你分享一张地图</string>
|
||||
<string name="share_map_body_format">我想你可能会对这个地图感兴趣:
|
||||
|
||||
@@ -239,7 +302,6 @@ limitations under the License.
|
||||
<string name="send_track_body_format">我想你可能会对这条轨迹感兴趣.
|
||||
|
||||
请用 Google Earth 或其它地图软件查看此轨迹.</string>
|
||||
<string name="share_track">与朋友分享轨迹</string>
|
||||
|
||||
<!-- Visibility -->
|
||||
<string name="public_map">公开</string>
|
||||
@@ -331,10 +393,13 @@ limitations under the License.
|
||||
<string name="about_team">开发团队:</string>
|
||||
<string name="about_version">版本:</string>
|
||||
<string name="about_support">技术支持:</string>
|
||||
<string name="about_privacy">隐私策略:</string>
|
||||
|
||||
<!-- Send to Google -->
|
||||
<string name="sendtogoogle_title">发送到...</string>
|
||||
<string name="sendtogoogle_send_now">立即发送</string>
|
||||
<string name="sendtogoogle_create_new_map">创建新地图</string>
|
||||
<string name="sendtogoogle_pick_existing_map">选择已有地图</string>
|
||||
<string name="sendtogoogle_send_stats">发送轨迹统计信息</string>
|
||||
<string name="sendtogoogle_send_stats_and_points">发送统计信息和路点</string>
|
||||
|
||||
@@ -344,10 +409,11 @@ limitations under the License.
|
||||
<string name="choose_account_title">选择帐户</string>
|
||||
|
||||
<!-- SD card -->
|
||||
<string name="io_no_external_storage_found">没有发现存贮设备. 请确认插入了 SD 卡并且你的手机没有将挂载 SD 卡到电脑.</string>
|
||||
<string name="io_no_external_storage_found">没有发现存储设备. 请确认插入了 SD 存储卡并且你的手机没有将挂载 SD 卡到电脑.</string>
|
||||
<string name="io_write_failed">无法写入文件.</string>
|
||||
<string name="io_create_dir_failed">无法在 SD 存储卡上创建目录.</string>
|
||||
<string name="io_write_finished">轨迹已导出到 SD 卡.</string>
|
||||
<string name="io_create_dir_failed">无法在 SD 存储卡上创建目录card.</string>
|
||||
<string name="io_write_finished">轨迹已导出到 SD 存储卡.</string>
|
||||
<string name="io_read_finished">从 SD 存储卡读取完毕.</string>
|
||||
|
||||
<!-- VersionChecker -->
|
||||
@@ -395,4 +461,20 @@ limitations under the License.
|
||||
<string name="sensor_data_time">感应器数据时间</string>
|
||||
<string name="power_meter_enabled">电源计量器已启用</string>
|
||||
<string name="heart_rate_monitor_enabled">心率监视器已启用</string>
|
||||
<string name="no_sensor_manager">没有感应器管理器</string>
|
||||
<string name="enabled">已启用</string>
|
||||
<string name="connecting">连接中</string>
|
||||
<string name="connected">已连接</string>
|
||||
<string name="disconnected">未连接</string>
|
||||
<string name="no_sensor_service">没有感应器服务</string>
|
||||
<string name="searching">搜索中</string>
|
||||
<string name="sending">发送中</string>
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">无</string>
|
||||
<string name="ant_sensor_option">ANT+ 感应器</string>
|
||||
<string name="ant_bridge_sensor_option">SRM ANT+ 转接器</string>
|
||||
<string name="polar_bt_sensor_option">Polar Bluetooth</string>
|
||||
<string name="zephyr_bt_sensor_option">Zephyr 蓝牙设备</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -170,6 +170,11 @@ limitations under the License.
|
||||
<item>inline skating</item>
|
||||
<item>skate boarding</item>
|
||||
|
||||
<item>roller skiing (classic)</item>
|
||||
<item>roller skiing (skate)</item>
|
||||
<item>cross-country skiing (classic)</item>
|
||||
<item>cross-country skiing (skate)</item>
|
||||
|
||||
<item>snow shoeing</item>
|
||||
<item>skiing</item>
|
||||
<item>snow boarding</item>
|
||||
@@ -272,11 +277,4 @@ limitations under the License.
|
||||
<item>way point</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>None</item>
|
||||
<item>ANT+ Sensors</item>
|
||||
<item>SRM ANT+ Bridge</item>
|
||||
<item>Zephyr Bluetooth</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -38,16 +38,6 @@ limitations under the License.
|
||||
<item>100</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="min_recording_distance_values">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>10</item>
|
||||
<item>100</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="max_recording_distance_values">
|
||||
<item>50</item>
|
||||
<item>100</item>
|
||||
@@ -108,10 +98,19 @@ limitations under the License.
|
||||
<item>TCX</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>@string/no_sensor_option</item>
|
||||
<item>@string/ant_sensor_option</item>
|
||||
<item>@string/ant_bridge_sensor_option</item>
|
||||
<item>@string/polar_bt_sensor_option</item>
|
||||
<item>@string/zephyr_bt_sensor_option</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_values">
|
||||
<item>@string/none</item>
|
||||
<item>@string/ant_sensor_type</item>
|
||||
<item>@string/srm_ant_bridge_sensor_type</item>
|
||||
<item>@string/polar_sensor_type</item>
|
||||
<item>@string/zephyr_sensor_type</item>
|
||||
</array>
|
||||
|
||||
|
||||
@@ -47,4 +47,8 @@ limitations under the License.
|
||||
<!-- Purple and a transparent purple -->
|
||||
<color name="power_border">#FF401465</color>
|
||||
<color name="power_fill">#40401465</color>
|
||||
|
||||
<!-- AppWidget colors -->
|
||||
<color name="appwidget_text">#EDEDED</color>
|
||||
<color name="appwidget_hr">#99999999</color>
|
||||
</resources>
|
||||
|
||||
@@ -33,10 +33,17 @@ limitations under the License.
|
||||
<string name="none">NONE</string>
|
||||
<string name="ant_sensor_type">ANT</string>
|
||||
<string name="srm_ant_bridge_sensor_type">SRM_ANT_BRIDGE</string>
|
||||
<string name="polar_sensor_type">POLAR</string>
|
||||
<string name="zephyr_sensor_type">ZEPHYR</string>
|
||||
|
||||
<!-- Send to Google URLs -->
|
||||
<string name="sendtogoogle_google_fusiontables_url">google.com/fusiontables</string>
|
||||
<string name="sendtogoogle_google_mymaps_url">maps.google.com</string>
|
||||
<string name="sendtogoogle_google_docs_url">docs.google.com</string>
|
||||
|
||||
<!-- ID for Google Analytics -->
|
||||
<string name="google_analytics_id">UA-7222692-2</string>
|
||||
|
||||
<!-- Intent actions -->
|
||||
<string name="save_intent_action">android.intent.action.SAVE</string>
|
||||
</resources>
|
||||
|
||||
@@ -83,7 +83,8 @@ limitations under the License.
|
||||
<string name="write_progress_message">Writing file to SD card. This may take a while.</string>
|
||||
<string name="progress_message_updating_track">Updating track statistics...</string>
|
||||
|
||||
<!-- Used by DeleteAllDataHandler -->
|
||||
<!-- Used by deletion actions -->
|
||||
<string name="deletetrack_title">Delete track</string>
|
||||
<string name="are_you_sure_question">Are you sure?</string>
|
||||
<string name="all_data_will_be_permanently_deleted">All tracks and markers will be deleted from this phone.</string>
|
||||
<string name="track_will_be_permanently_deleted">The track and its markers will be permanently deleted from this phone.</string>
|
||||
@@ -163,9 +164,12 @@ limitations under the License.
|
||||
$2 : Attempted imports
|
||||
$3 : MyTracks gpx path
|
||||
-->
|
||||
<string name="import_done">Imported %1$d of %2$d GPX files from %3$s</string>
|
||||
<string name="import_empty">No GPX files found in %s. SD card may be unreadable or directory may not contain GPX files.</string>
|
||||
<string name="import_multi_done">Imported %1$d of %2$d GPX files from %3$s</string>
|
||||
<string name="import_multi_empty">No GPX files found in %s. SD card may be unreadable or directory may not contain GPX files.</string>
|
||||
<string name="import_error">Import error for file %s</string>
|
||||
<string name="import_title">Import into My Tracks</string>
|
||||
<string name="import_success">Successfully imported %1$d track(s) from file.</string>
|
||||
<string name="import_show_track">Show track</string>
|
||||
|
||||
<!-- Waypoints list -->
|
||||
<string name="waypointslist_btn_delete_all">Delete all markers</string>
|
||||
@@ -498,4 +502,12 @@ limitations under the License.
|
||||
<string name="notification_permission_description">Be notified when a track starts or stops being recorded.</string>
|
||||
<string name="read_tracks_permission_description">Be able to read track data, such as points and waypoints.</string>
|
||||
<string name="write_tracks_permission_description">Be able to write track data, such as starting recording or adding waypoints.</string>
|
||||
|
||||
<!-- Sensor Type Options -->
|
||||
<string name="no_sensor_option">NONE</string>
|
||||
<string name="ant_sensor_option">ANT+ Sensors</string>
|
||||
<string name="ant_bridge_sensor_option">SRM ANT+ Bridge</string>
|
||||
<string name="polar_bt_sensor_option">Polar Bluetooth</string>
|
||||
<string name="zephyr_bt_sensor_option">Zephyr Bluetooth</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -74,4 +74,15 @@ limitations under the License.
|
||||
<item name="android:layout_height">3dip</item>
|
||||
<item name="android:layout_width">fill_parent</item>
|
||||
</style>
|
||||
|
||||
<!-- The style for the track widget. -->
|
||||
<style name="WidgetText" parent="@android:Widget.TextView">
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:textColor">@color/appwidget_text</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
</style>
|
||||
<style name="WidgetText.Register">
|
||||
<item name="android:width">160px</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -42,7 +42,7 @@ limitations under the License.
|
||||
android:summary="@string/settings_announcement_frequency_summary"
|
||||
android:entries="@array/task_frequency_options"
|
||||
android:entryValues="@array/task_frequency_values"
|
||||
android:defaultValue="-1" />
|
||||
android:defaultValue="0" />
|
||||
|
||||
<com.google.android.apps.mytracks.IntegerListPreference
|
||||
android:key="@string/split_frequency_key"
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2011 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<appwidget-provider
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:initialLayout="@layout/track_widget"
|
||||
android:minHeight="72dp"
|
||||
android:minWidth="294dp"
|
||||
android:updatePeriodMillis="0" />
|
||||
@@ -61,10 +61,10 @@ public class AntInterface {
|
||||
private static Object INSTANCE_LOCK = new Object();
|
||||
|
||||
/** The context to use. */
|
||||
private static Context sContext = null;
|
||||
private Context sContext = null;
|
||||
|
||||
/** Listens to changes to service connection status. */
|
||||
private static ServiceListener sServiceListener;
|
||||
private ServiceListener sServiceListener;
|
||||
|
||||
/** Is the ANT Radio Proxy Service connected. */
|
||||
private static boolean sServiceConnected = false;
|
||||
@@ -210,7 +210,7 @@ public class AntInterface {
|
||||
/**
|
||||
* Class for interacting with the ANT interface.
|
||||
*/
|
||||
private static ServiceConnection sIAntConnection = new ServiceConnection() {
|
||||
private final ServiceConnection sIAntConnection = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName pClassName, IBinder pService) {
|
||||
// This is called when the connection with the service has been
|
||||
// established, giving us the service object we can use to
|
||||
@@ -1223,7 +1223,7 @@ public class AntInterface {
|
||||
*/
|
||||
public boolean requestForceClaimInterface(String appName) throws AntInterfaceException
|
||||
{
|
||||
if((null == appName) || ("" == appName))
|
||||
if((null == appName) || ("".equals(appName)))
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import com.google.android.accounts.Account;
|
||||
import com.google.android.accounts.AccountManager;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
@@ -29,7 +29,7 @@ import android.util.Log;
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class AccountChooser {
|
||||
|
||||
|
||||
/**
|
||||
* The last selected account.
|
||||
*/
|
||||
@@ -44,7 +44,7 @@ public class AccountChooser {
|
||||
* Handle the account being selected.
|
||||
* @param account The selected account or null if none could be found
|
||||
*/
|
||||
public void handleAccountSelected(Account account);
|
||||
public void onAccountSelected(Account account);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,7 @@ public class AccountChooser {
|
||||
* If no account is found the user will be alerted.
|
||||
* If only one account is found that will be used.
|
||||
* If multiple accounts are found the user will be allowed to choose.
|
||||
*
|
||||
*
|
||||
* @param activity The parent activity
|
||||
* @param handler The handler to be notified when an account has been selected
|
||||
*/
|
||||
@@ -65,16 +65,16 @@ public class AccountChooser {
|
||||
return;
|
||||
}
|
||||
if (accounts.length == 1) {
|
||||
handler.handleAccountSelected(accounts[0]);
|
||||
handler.onAccountSelected(accounts[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// TODO This should be read out of a preference.
|
||||
if (selectedAccount != null) {
|
||||
handler.handleAccountSelected(selectedAccount);
|
||||
handler.onAccountSelected(selectedAccount);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Let the user choose.
|
||||
Log.e(Constants.TAG, "Multiple matching accounts found.");
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
@@ -83,14 +83,20 @@ public class AccountChooser {
|
||||
builder.setPositiveButton(R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
selectedAccount = accounts[selectedAccountIndex];
|
||||
handler.handleAccountSelected(selectedAccount);
|
||||
dialog.dismiss();
|
||||
|
||||
if (selectedAccountIndex >= 0) {
|
||||
selectedAccount = accounts[selectedAccountIndex];
|
||||
}
|
||||
|
||||
handler.onAccountSelected(selectedAccount);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
handler.handleAccountSelected(null);
|
||||
dialog.dismiss();
|
||||
handler.onAccountSelected(null);
|
||||
}
|
||||
});
|
||||
String[] choices = new String[accounts.length];
|
||||
@@ -107,6 +113,10 @@ public class AccountChooser {
|
||||
builder.show();
|
||||
}
|
||||
|
||||
public void setChosenAccount(String accountName, String accountType) {
|
||||
selectedAccount = new Account(accountName, accountType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts up a dialog alerting the user that no suitable account was found.
|
||||
*/
|
||||
@@ -120,7 +130,8 @@ public class AccountChooser {
|
||||
builder.setNegativeButton(R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
handler.handleAccountSelected(null);
|
||||
dialog.dismiss();
|
||||
handler.onAccountSelected(null);
|
||||
}
|
||||
});
|
||||
builder.show();
|
||||
|
||||
@@ -19,9 +19,9 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Activity for viewing the combined statistics for all the recorded tracks.
|
||||
*
|
||||
*
|
||||
* Other features to add - menu items to change setings.
|
||||
*
|
||||
*
|
||||
* @author Fergus Nelson
|
||||
*/
|
||||
public class AggregatedStatsActivity extends Activity implements
|
||||
@@ -43,7 +43,7 @@ public class AggregatedStatsActivity extends Activity implements
|
||||
Log.d(Constants.TAG, "StatsActivity: onSharedPreferences changed "
|
||||
+ key);
|
||||
if (key != null) {
|
||||
if (key.equals(R.string.metric_units_key)) {
|
||||
if (key.equals(getString(R.string.metric_units_key))) {
|
||||
metricUnits = sharedPreferences.getBoolean(
|
||||
getString(R.string.metric_units_key), true);
|
||||
utils.setMetricUnits(metricUnits);
|
||||
@@ -86,8 +86,8 @@ public class AggregatedStatsActivity extends Activity implements
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Reads tracks from the db
|
||||
* 2. Merges the trip stats from the tracks
|
||||
* 1. Reads tracks from the db
|
||||
* 2. Merges the trip stats from the tracks
|
||||
* 3. Updates the view
|
||||
*/
|
||||
private void loadAggregatedStats() {
|
||||
|
||||
@@ -35,6 +35,9 @@ import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
@@ -58,6 +61,7 @@ import java.util.EnumSet;
|
||||
*/
|
||||
public class ChartActivity extends Activity implements TrackDataListener {
|
||||
|
||||
private static final int CHART_SETTINGS_DIALOG = 1;
|
||||
private final DoubleBuffer elevationBuffer =
|
||||
new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
|
||||
private final DoubleBuffer speedBuffer =
|
||||
@@ -73,7 +77,6 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
||||
private double trackMaxSpeed;
|
||||
|
||||
// Modes of operation
|
||||
private Mode mode = Mode.BY_DISTANCE;
|
||||
private boolean metricUnits;
|
||||
private boolean reportSpeed;
|
||||
|
||||
@@ -93,10 +96,16 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
||||
private final Runnable updateChart = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Get a local reference in case it's set to null concurrently with this.
|
||||
TrackDataHub localDataHub = dataHub;
|
||||
if (localDataHub == null || isFinishing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
busyPane.setVisibility(View.GONE);
|
||||
zoomControls.setIsZoomInEnabled(chartView.canZoomIn());
|
||||
zoomControls.setIsZoomOutEnabled(chartView.canZoomOut());
|
||||
chartView.setShowPointer(dataHub.isRecordingSelected());
|
||||
chartView.setShowPointer(localDataHub.isRecordingSelected());
|
||||
chartView.invalidate();
|
||||
}
|
||||
};
|
||||
@@ -105,8 +114,6 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Log.w(TAG, "ChartActivity.onCreate");
|
||||
super.onCreate(savedInstanceState);
|
||||
MyTracks.getInstance().setChartActivity(this);
|
||||
dataHub = MyTracks.getInstance().getDataHub();
|
||||
|
||||
// The volume we want to control is the Text-To-Speech volume
|
||||
int volumeStream =
|
||||
@@ -117,7 +124,6 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
||||
setContentView(R.layout.mytracks_charts);
|
||||
ViewGroup layout = (ViewGroup) findViewById(R.id.elevation_chart);
|
||||
chartView = new ChartView(this);
|
||||
chartView.setMode(this.mode);
|
||||
LayoutParams params =
|
||||
new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
|
||||
layout.addView(chartView, params);
|
||||
@@ -142,8 +148,10 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
dataHub = TrackDataHub.getStartedInstance();
|
||||
dataHub.registerTrackDataListener(this, EnumSet.of(
|
||||
ListenerDataType.SELECTED_TRACK_CHANGED,
|
||||
ListenerDataType.TRACK_UPDATES,
|
||||
ListenerDataType.POINT_UPDATES,
|
||||
ListenerDataType.SAMPLED_OUT_POINT_UPDATES,
|
||||
ListenerDataType.WAYPOINT_UPDATES,
|
||||
@@ -153,6 +161,7 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
||||
@Override
|
||||
protected void onPause() {
|
||||
dataHub.unregisterTrackDataListener(this);
|
||||
dataHub = null;
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
@@ -169,27 +178,13 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
||||
zoomControls.setIsZoomOutEnabled(chartView.canZoomOut());
|
||||
}
|
||||
|
||||
public void setMode(Mode newMode) {
|
||||
if (this.mode != newMode) {
|
||||
this.mode = newMode;
|
||||
chartView.setMode(this.mode);
|
||||
private void setMode(Mode newMode) {
|
||||
if (chartView.getMode() != newMode) {
|
||||
chartView.setMode(newMode);
|
||||
dataHub.reloadDataForListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
public Mode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setSeriesEnabled(int index, boolean enabled) {
|
||||
chartView.getChartValueSeries(index).setEnabled(enabled);
|
||||
runOnUiThread(updateChart);
|
||||
}
|
||||
|
||||
public boolean isSeriesEnabled(int index) {
|
||||
return chartView.getChartValueSeries(index).isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
@@ -204,13 +199,52 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case Constants.MENU_CHART_SETTINGS:
|
||||
MyTracks.getInstance().getDialogManager().showDialogSafely(
|
||||
DialogManager.DIALOG_CHART_SETTINGS);
|
||||
showDialog(CHART_SETTINGS_DIALOG);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
if (id == CHART_SETTINGS_DIALOG) {
|
||||
final ChartSettingsDialog settingsDialog = new ChartSettingsDialog(this);
|
||||
settingsDialog.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface arg0, int which) {
|
||||
if (which != DialogInterface.BUTTON_POSITIVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ChartView.NUM_SERIES; i++) {
|
||||
chartView.setChartValueSeriesEnabled(i, settingsDialog.isSeriesEnabled(i));
|
||||
}
|
||||
setMode(settingsDialog.getMode());
|
||||
chartView.postInvalidate();
|
||||
}
|
||||
});
|
||||
return settingsDialog;
|
||||
}
|
||||
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPrepareDialog(int id, Dialog dialog) {
|
||||
super.onPrepareDialog(id, dialog);
|
||||
|
||||
if (id == CHART_SETTINGS_DIALOG) {
|
||||
prepareSettingsDialog((ChartSettingsDialog) dialog);
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareSettingsDialog(ChartSettingsDialog settingsDialog) {
|
||||
settingsDialog.setMode(chartView.getMode());
|
||||
for (int i = 0; i < ChartView.NUM_SERIES; i++) {
|
||||
settingsDialog.setSeriesEnabled(i, chartView.isChartValueSeriesEnabled(i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a location, creates a new data point for the chart. A data point is
|
||||
* an array double[3 or 6], where:
|
||||
@@ -257,6 +291,7 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
||||
}
|
||||
|
||||
// TODO: Account for segment splits?
|
||||
Mode mode = chartView.getMode();
|
||||
switch (mode) {
|
||||
case BY_DISTANCE:
|
||||
timeOrDistance = profileLength / 1000.0;
|
||||
@@ -424,10 +459,11 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
||||
this.metricUnits = metric;
|
||||
|
||||
chartView.setMetricUnits(metric);
|
||||
|
||||
|
||||
return true; // Reload data
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
@Override
|
||||
public boolean onReportSpeedChanged(boolean reportSpeed) {
|
||||
boolean changed = reportSpeed != this.reportSpeed;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2009 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -36,6 +36,7 @@ import android.widget.RadioGroup;
|
||||
public class ChartSettingsDialog extends Dialog {
|
||||
private RadioButton distance;
|
||||
private CheckBox[] series;
|
||||
private OnClickListener clickListener;
|
||||
|
||||
public ChartSettingsDialog(Context context) {
|
||||
super(context);
|
||||
@@ -44,23 +45,31 @@ public class ChartSettingsDialog extends Dialog {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.chart_settings);
|
||||
Button cancel = (Button) findViewById(R.id.chart_settings_cancel);
|
||||
cancel.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
if (clickListener != null) {
|
||||
clickListener.onClick(ChartSettingsDialog.this, BUTTON_NEGATIVE);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
Button ok = (Button) findViewById(R.id.chart_settings_ok);
|
||||
ok.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
Button okButton = (Button) findViewById(R.id.chart_settings_ok);
|
||||
okButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
handleOk();
|
||||
if (clickListener != null) {
|
||||
clickListener.onClick(ChartSettingsDialog.this, BUTTON_POSITIVE);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
distance = (RadioButton) findViewById(R.id.chart_settings_by_distance);
|
||||
|
||||
|
||||
series = new CheckBox[ChartView.NUM_SERIES];
|
||||
series[ChartView.ELEVATION_SERIES] =
|
||||
(CheckBox) findViewById(R.id.chart_settings_elevation);
|
||||
@@ -74,29 +83,30 @@ public class ChartSettingsDialog extends Dialog {
|
||||
(CheckBox) findViewById(R.id.chart_settings_heart_rate);
|
||||
}
|
||||
|
||||
public void setup(ChartActivity chart) {
|
||||
if (chart == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void setMode(Mode mode) {
|
||||
RadioGroup rd = (RadioGroup) findViewById(R.id.chart_settings_x);
|
||||
rd.check(chart.getMode() == Mode.BY_DISTANCE
|
||||
rd.check(mode == Mode.BY_DISTANCE
|
||||
? R.id.chart_settings_by_distance
|
||||
: R.id.chart_settings_by_time);
|
||||
for (int i = 0; i < ChartView.NUM_SERIES; i++) {
|
||||
series[i].setChecked(chart.isSeriesEnabled(i));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleOk() {
|
||||
ChartActivity chart = MyTracks.getInstance().getChartActivity();
|
||||
chart.setMode(distance.isChecked() ? Mode.BY_DISTANCE : Mode.BY_TIME);
|
||||
public void setSeriesEnabled(int seriesIdx, boolean enabled) {
|
||||
series[seriesIdx].setChecked(enabled);
|
||||
}
|
||||
|
||||
// TODO: check that something is visible.
|
||||
for (int i = 0; i < ChartView.NUM_SERIES; i++) {
|
||||
chart.setSeriesEnabled(i, series[i].isChecked());
|
||||
}
|
||||
public Mode getMode() {
|
||||
if (distance == null) return Mode.BY_DISTANCE;
|
||||
|
||||
dismiss();
|
||||
return distance.isChecked() ? Mode.BY_DISTANCE : Mode.BY_TIME;
|
||||
}
|
||||
|
||||
public boolean isSeriesEnabled(int seriesIdx) {
|
||||
if (series == null) return true;
|
||||
|
||||
return series[seriesIdx].isChecked();
|
||||
}
|
||||
|
||||
public void setOnClickListener(OnClickListener clickListener) {
|
||||
this.clickListener = clickListener;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ import java.util.ArrayList;
|
||||
* @author Leif Hendrik Wilden
|
||||
*/
|
||||
public class ChartView extends View {
|
||||
private static final int MIN_ZOOM_LEVEL = 1;
|
||||
|
||||
/*
|
||||
* Scrolling logic:
|
||||
@@ -62,7 +63,6 @@ public class ChartView extends View {
|
||||
* Zoom logic:
|
||||
*/
|
||||
private int zoomLevel = 1;
|
||||
private final int minZoomLevel = 1;
|
||||
private int maxZoomLevel = 10;
|
||||
|
||||
private static final int MAX_INTERVALS = 5;
|
||||
@@ -199,7 +199,7 @@ public class ChartView extends View {
|
||||
updateDimensions();
|
||||
}
|
||||
|
||||
public void setUpChartValueSeries(Context context) {
|
||||
private void setUpChartValueSeries(Context context) {
|
||||
series = new ChartValueSeries[NUM_SERIES];
|
||||
|
||||
// Create the value series.
|
||||
@@ -333,7 +333,7 @@ public class ChartView extends View {
|
||||
* @return true if the chart can be zoomed out
|
||||
*/
|
||||
public boolean canZoomOut() {
|
||||
return zoomLevel > minZoomLevel;
|
||||
return zoomLevel > MIN_ZOOM_LEVEL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,6 +401,7 @@ public class ChartView extends View {
|
||||
|
||||
/**
|
||||
* Sets the display mode (by distance, by time).
|
||||
* It is expected that after the mode change, data will be reloaded.
|
||||
*/
|
||||
public void setMode(Mode mode) {
|
||||
this.mode = mode;
|
||||
@@ -593,7 +594,7 @@ public class ChartView extends View {
|
||||
|
||||
final float x = getWaypointX(waypoint);
|
||||
c.drawLine(x, h - bottomBorder, x, topBorder, gridPaint);
|
||||
c.translate(x - markerWidth / 2, markerHeight);
|
||||
c.translate(x - (float) markerWidth / 2.0f, (float) markerHeight);
|
||||
if (waypoints.get(i).getType() == Waypoint.TYPE_STATISTICS) {
|
||||
statsMarker.draw(c);
|
||||
} else {
|
||||
@@ -865,14 +866,24 @@ public class ChartView extends View {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one of the chart value series.
|
||||
* The index should be one of the following values:
|
||||
* ELEVATION_SERIES or SPEED_SERIES
|
||||
* Returns whether a given time series is enabled for drawing.
|
||||
*
|
||||
* @param index of the value series
|
||||
* @return The chart series at the index
|
||||
* @param index the time series, one of {@link #ELEVATION_SERIES},
|
||||
* {@link #SPEED_SERIES}, {@link #POWER_SERIES}, etc.
|
||||
* @return true if drawn, false otherwise
|
||||
*/
|
||||
public ChartValueSeries getChartValueSeries(int index) {
|
||||
return series[index];
|
||||
public boolean isChartValueSeriesEnabled(int index) {
|
||||
return series[index].isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether a given time series will be enabled for drawing.
|
||||
*
|
||||
* @param index the time series, one of {@link #ELEVATION_SERIES},
|
||||
* {@link #SPEED_SERIES}, {@link #POWER_SERIES}, etc.
|
||||
* @return true to be drawn, false otherwise
|
||||
*/
|
||||
public void setChartValueSeriesEnabled(int index, boolean enabled) {
|
||||
series[index].setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -26,7 +26,7 @@ public abstract class Constants {
|
||||
* Should be used by all log statements
|
||||
*/
|
||||
public static final String TAG = "MyTracks";
|
||||
|
||||
|
||||
/**
|
||||
* Name of the top-level directory inside the SD card where our files will
|
||||
* be read from/written to.
|
||||
@@ -39,32 +39,21 @@ public abstract class Constants {
|
||||
|
||||
public static final int GET_LOGIN = 0;
|
||||
public static final int GET_MAP = 1;
|
||||
public static final int CREATE_MAP = 2;
|
||||
public static final int SHOW_TRACK = 3;
|
||||
public static final int ADD_LIST = 4;
|
||||
public static final int FEATURE_DETAILS = 5;
|
||||
public static final int START_RECORDING = 6;
|
||||
public static final int STOP_RECORDING = 7;
|
||||
public static final int AUTHENTICATE_TO_MY_MAPS = 8;
|
||||
public static final int AUTHENTICATE_TO_FUSION_TABLES = 9;
|
||||
public static final int AUTHENTICATE_TO_DOCLIST = 10;
|
||||
public static final int AUTHENTICATE_TO_TRIX = 11;
|
||||
public static final int DELETE_TRACK = 13;
|
||||
public static final int SEND_TO_GOOGLE_DIALOG = 14;
|
||||
public static final int SHARE_LINK = 15;
|
||||
public static final int SHARE_GPX_FILE = 16;
|
||||
public static final int SHARE_KML_FILE = 17;
|
||||
public static final int SHARE_CSV_FILE = 18;
|
||||
public static final int SHARE_TCX_FILE = 19;
|
||||
public static final int EDIT_DETAILS = 20;
|
||||
public static final int SAVE_GPX_FILE = 21;
|
||||
public static final int SAVE_KML_FILE = 22;
|
||||
public static final int SAVE_CSV_FILE = 23;
|
||||
public static final int SAVE_TCX_FILE = 24;
|
||||
public static final int CLEAR_MAP = 25;
|
||||
public static final int SHOW_WAYPOINT = 26;
|
||||
public static final int EDIT_WAYPOINT = 27;
|
||||
public static final int WELCOME = 28;
|
||||
public static final int SHOW_TRACK = 2;
|
||||
public static final int AUTHENTICATE_TO_MY_MAPS = 3;
|
||||
public static final int AUTHENTICATE_TO_FUSION_TABLES = 4;
|
||||
public static final int AUTHENTICATE_TO_DOCLIST = 5;
|
||||
public static final int AUTHENTICATE_TO_TRIX = 6;
|
||||
public static final int SHARE_GPX_FILE = 7;
|
||||
public static final int SHARE_KML_FILE = 8;
|
||||
public static final int SHARE_CSV_FILE = 9;
|
||||
public static final int SHARE_TCX_FILE = 10;
|
||||
public static final int SAVE_GPX_FILE = 11;
|
||||
public static final int SAVE_KML_FILE = 12;
|
||||
public static final int SAVE_CSV_FILE = 13;
|
||||
public static final int SAVE_TCX_FILE = 14;
|
||||
public static final int SHOW_WAYPOINT = 15;
|
||||
public static final int WELCOME = 16;
|
||||
|
||||
/*
|
||||
* Menu ids:
|
||||
@@ -179,7 +168,7 @@ public abstract class Constants {
|
||||
* The type of account that we can use for gdata uploads.
|
||||
*/
|
||||
public static final String ACCOUNT_TYPE = "com.google";
|
||||
|
||||
|
||||
/**
|
||||
* The name of extra intent property to indicate whether we want to resume
|
||||
* a previously recorded track.
|
||||
@@ -189,14 +178,6 @@ public abstract class Constants {
|
||||
|
||||
public static int getActionFromMenuId(int menuId) {
|
||||
switch (menuId) {
|
||||
case Constants.MENU_SEND_TO_GOOGLE:
|
||||
return Constants.SEND_TO_GOOGLE_DIALOG;
|
||||
case Constants.MENU_EDIT:
|
||||
return Constants.EDIT_DETAILS;
|
||||
case Constants.MENU_DELETE:
|
||||
return Constants.DELETE_TRACK;
|
||||
case Constants.MENU_SHARE_LINK:
|
||||
return Constants.SHARE_LINK;
|
||||
case Constants.MENU_SHARE_KML_FILE:
|
||||
return Constants.SHARE_KML_FILE;
|
||||
case Constants.MENU_SHARE_GPX_FILE:
|
||||
@@ -213,8 +194,6 @@ public abstract class Constants {
|
||||
return Constants.SAVE_CSV_FILE;
|
||||
case Constants.MENU_SAVE_TCX_FILE:
|
||||
return Constants.SAVE_TCX_FILE;
|
||||
case Constants.MENU_CLEAR_MAP:
|
||||
return Constants.CLEAR_MAP;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -56,8 +56,8 @@ public class DeleteAllTracks extends Handler {
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
builder.setPositiveButton(context.getString(R.string.yes),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int i) {
|
||||
dialog.dismiss();
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
dialogInterface.dismiss();
|
||||
Log.w(Constants.TAG, "deleting all!");
|
||||
MyTracksProviderUtils.Factory.get(context).deleteAllTracks();
|
||||
SharedPreferences prefs =
|
||||
@@ -74,8 +74,8 @@ public class DeleteAllTracks extends Handler {
|
||||
});
|
||||
builder.setNegativeButton(context.getString(R.string.no),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int i) {
|
||||
dialog.dismiss();
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
dialogInterface.dismiss();
|
||||
}
|
||||
});
|
||||
dialog = builder.create();
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
import com.google.android.apps.mytracks.util.UriUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.ContentUris;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnCancelListener;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Activity used to delete a track.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class DeleteTrack extends Activity
|
||||
implements DialogInterface.OnClickListener, OnCancelListener {
|
||||
private static final int CONFIRM_DIALOG = 1;
|
||||
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
|
||||
private long deleteTrackId;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
||||
|
||||
Intent intent = getIntent();
|
||||
String action = intent.getAction();
|
||||
Uri data = intent.getData();
|
||||
if (!Intent.ACTION_DELETE.equals(action) ||
|
||||
!UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
|
||||
Log.e(TAG, "Got bad delete intent: " + intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
deleteTrackId = ContentUris.parseId(data);
|
||||
|
||||
showDialog(CONFIRM_DIALOG);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
if (id != CONFIRM_DIALOG) {
|
||||
Log.e(TAG, "Unknown dialog " + id);
|
||||
return null;
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setMessage(getString(R.string.track_will_be_permanently_deleted));
|
||||
builder.setTitle(getString(R.string.are_you_sure_question));
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
builder.setPositiveButton(getString(R.string.yes), this);
|
||||
builder.setNegativeButton(getString(R.string.no), this);
|
||||
builder.setOnCancelListener(this);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int which) {
|
||||
dialogInterface.dismiss();
|
||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||
deleteTrack();
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
onClick(dialog, DialogInterface.BUTTON_NEGATIVE);
|
||||
}
|
||||
|
||||
private void deleteTrack() {
|
||||
providerUtils.deleteTrack(deleteTrackId);
|
||||
|
||||
// If the track we just deleted was selected, unselect it.
|
||||
String selectedKey = getString(R.string.selected_track_key);
|
||||
SharedPreferences preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||
if (preferences.getLong(selectedKey, -1) == deleteTrackId) {
|
||||
Editor editor = preferences.edit().putLong(selectedKey, -1);
|
||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,14 +17,8 @@ package com.google.android.apps.mytracks;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendDialog;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.WindowManager.BadTokenException;
|
||||
|
||||
@@ -35,145 +29,16 @@ import android.view.WindowManager.BadTokenException;
|
||||
*/
|
||||
public class DialogManager {
|
||||
|
||||
public static final int DIALOG_CHART_SETTINGS = 1;
|
||||
public static final int DIALOG_IMPORT_PROGRESS = 2;
|
||||
public static final int DIALOG_PROGRESS = 3;
|
||||
public static final int DIALOG_SEND_TO_GOOGLE = 4;
|
||||
|
||||
private ProgressDialog progressDialog;
|
||||
private ProgressDialog importProgressDialog;
|
||||
private SendDialog sendToGoogleDialog;
|
||||
private ChartSettingsDialog chartSettingsDialog;
|
||||
|
||||
private MyTracks activity;
|
||||
|
||||
public DialogManager(MyTracks activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
protected Dialog onCreateDialog(int id, Bundle args) {
|
||||
switch (id) {
|
||||
case DIALOG_CHART_SETTINGS:
|
||||
chartSettingsDialog = new ChartSettingsDialog(activity);
|
||||
return chartSettingsDialog;
|
||||
case DIALOG_IMPORT_PROGRESS:
|
||||
importProgressDialog = new ProgressDialog(activity);
|
||||
importProgressDialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||
importProgressDialog.setTitle(
|
||||
activity.getString(R.string.progress_title));
|
||||
importProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
importProgressDialog.setMessage(
|
||||
activity.getString(R.string.import_progress_message));
|
||||
return importProgressDialog;
|
||||
case DIALOG_PROGRESS:
|
||||
progressDialog = new ProgressDialog(activity);
|
||||
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||
progressDialog.setTitle(activity.getString(R.string.progress_title));
|
||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
progressDialog.setMessage("");
|
||||
progressDialog.setMax(100);
|
||||
progressDialog.setProgress(10);
|
||||
return progressDialog;
|
||||
case DIALOG_SEND_TO_GOOGLE:
|
||||
sendToGoogleDialog = new SendDialog(activity);
|
||||
return sendToGoogleDialog;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onPrepareDialog(int id, Dialog dialog) {
|
||||
switch (id) {
|
||||
case DIALOG_SEND_TO_GOOGLE:
|
||||
activity.resetSendToGoogleStatus();
|
||||
break;
|
||||
case DIALOG_CHART_SETTINGS:
|
||||
Log.d(TAG, "MyTracks.onPrepare chart dialog");
|
||||
chartSettingsDialog.setup(activity.getChartActivity());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void setProgressMessage(final String message) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
synchronized (this) {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.setMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setProgressValue(final int percent) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
synchronized (this) {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.setProgress(percent);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sendToGoogleDialog
|
||||
*/
|
||||
public SendDialog getSendToGoogleDialog() {
|
||||
return sendToGoogleDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a dialog with the given message.
|
||||
* Does it on the UI thread.
|
||||
*
|
||||
* @param success if true, displays an info icon/title, otherwise an error
|
||||
* icon/title
|
||||
* @param message resource string id
|
||||
*/
|
||||
public void showMessageDialog(final int message, final boolean success) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
AlertDialog dialog = null;
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setMessage(activity.getString(message));
|
||||
builder.setNegativeButton(activity.getString(R.string.ok), null);
|
||||
builder.setIcon(success ? android.R.drawable.ic_dialog_info :
|
||||
android.R.drawable.ic_dialog_alert);
|
||||
builder.setTitle(success ? R.string.success : R.string.error);
|
||||
dialog = builder.create();
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Just like showDialog, but will catch a {@link BadTokenException} that
|
||||
* sometimes (very rarely) gets thrown. This might happen if the user hits
|
||||
* the "back" button immediately after sending tracks to google.
|
||||
*
|
||||
* @param id the dialog id
|
||||
*/
|
||||
public void showDialogSafely(final int id) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
activity.showDialog(id);
|
||||
} catch (BadTokenException e) {
|
||||
Log.w(TAG, "Could not display dialog with id " + id, e);
|
||||
} catch (IllegalStateException e) {
|
||||
Log.w(TAG, "Could not display dialog with id " + id, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The equivalent of {@link #showDialogSafely(int)}, but for a specific
|
||||
* dialog instance.
|
||||
*/
|
||||
public static void showDialogSafely(Activity activity, final Dialog dialog) {
|
||||
if (activity.isFinishing()) {
|
||||
Log.w(TAG, "Activity finishing - not showing dialog");
|
||||
return;
|
||||
}
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
@@ -187,26 +52,16 @@ public class DialogManager {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses the progress dialog if it is showing. Executed on the UI thread.
|
||||
*/
|
||||
public void dismissDialogSafely(final int id) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
activity.dismissDialog(id);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// This will be thrown if this dialog was not shown before.
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The equivalent of {@link #dismissDialogSafely(int)}, but for a specific
|
||||
* dialog instance.
|
||||
*/
|
||||
public static void dismissDialogSafely(Activity activity, final Dialog dialog) {
|
||||
if (activity.isFinishing()) {
|
||||
Log.w(TAG, "Activity finishing - not dismissing dialog");
|
||||
return;
|
||||
}
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
@@ -217,4 +72,6 @@ public class DialogManager {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private DialogManager() {}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2009 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -29,8 +29,6 @@ import android.app.ProgressDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
@@ -91,12 +89,7 @@ public class ExportAllTracks {
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
HandlerThread handlerThread;
|
||||
Handler handler;
|
||||
handlerThread = new HandlerThread("SendToMyMaps");
|
||||
handlerThread.start();
|
||||
handler = new Handler(handlerThread.getLooper());
|
||||
handler.post(runner);
|
||||
new Thread(runner, "SendToMyMaps").start();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -117,7 +110,7 @@ public class ExportAllTracks {
|
||||
long recordingTrackId = -1;
|
||||
if (prefs != null) {
|
||||
recordingTrackId =
|
||||
prefs.getLong(activity.getString(R.string.recording_track_key), -1);
|
||||
prefs.getLong(activity.getString(R.string.recording_track_key), -1);
|
||||
}
|
||||
if (recordingTrackId != -1) {
|
||||
wakeLock = SystemUtils.acquireWakeLock(activity, wakeLock);
|
||||
@@ -133,7 +126,7 @@ public class ExportAllTracks {
|
||||
Log.i(Constants.TAG, "ExportAllTracks: Releasing wake lock.");
|
||||
}
|
||||
Log.i(Constants.TAG, "ExportAllTracks: Done");
|
||||
Toast.makeText(activity, R.string.export_done, Toast.LENGTH_SHORT).show();
|
||||
showToast(R.string.export_done, Toast.LENGTH_SHORT);
|
||||
}
|
||||
|
||||
private void makeProgressDialog(final int trackCount) {
|
||||
@@ -189,12 +182,16 @@ public class ExportAllTracks {
|
||||
Log.i(Constants.TAG, "ExportAllTracks: exporting: " + id);
|
||||
TrackWriter writer =
|
||||
TrackWriterFactory.newWriter(activity, providerUtils, id, format);
|
||||
if (writer == null) {
|
||||
showToast(R.string.error_track_does_not_exist, Toast.LENGTH_LONG);
|
||||
return;
|
||||
}
|
||||
|
||||
writer.writeTrack();
|
||||
|
||||
if (!writer.wasSuccess()) {
|
||||
// Abort the whole export on the first error.
|
||||
int error = writer.getErrorMessage();
|
||||
Toast.makeText(activity, error, Toast.LENGTH_LONG).show();
|
||||
showToast(writer.getErrorMessage(), Toast.LENGTH_LONG);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -210,4 +207,13 @@ public class ExportAllTracks {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showToast(final int messageId, final int length) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(activity, messageId, length).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -25,8 +25,6 @@ import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
@@ -45,7 +43,7 @@ import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* A class that will import all GPX tracks in /sdcard/MyTracks/gpx/
|
||||
*
|
||||
*
|
||||
* @author David Piggott
|
||||
*/
|
||||
public class ImportAllTracks {
|
||||
@@ -63,12 +61,8 @@ public class ImportAllTracks {
|
||||
Log.i(Constants.TAG, "ImportAllTracks: Starting");
|
||||
fileUtils = new FileUtils();
|
||||
gpxPath = fileUtils.buildExternalDirectoryPath("gpx");
|
||||
HandlerThread handlerThread;
|
||||
Handler handler;
|
||||
handlerThread = new HandlerThread("ImportAllTracks");
|
||||
handlerThread.start();
|
||||
handler = new Handler(handlerThread.getLooper());
|
||||
handler.post(runner);
|
||||
|
||||
new Thread(runner).start();
|
||||
}
|
||||
|
||||
private final Runnable runner = new Runnable() {
|
||||
@@ -104,9 +98,9 @@ public class ImportAllTracks {
|
||||
Log.i(Constants.TAG, "ImportAllTracks: Done");
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
if (gpxFileCount == 0) {
|
||||
builder.setMessage(activity.getString(R.string.import_empty, gpxPath + "/"));
|
||||
builder.setMessage(activity.getString(R.string.import_multi_empty, gpxPath + "/"));
|
||||
} else {
|
||||
builder.setMessage(activity.getString(R.string.import_done, importSuccessCount, gpxFileCount,
|
||||
builder.setMessage(activity.getString(R.string.import_multi_done, importSuccessCount, gpxFileCount,
|
||||
gpxPath + "/"));
|
||||
}
|
||||
builder.setPositiveButton(R.string.ok, null);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -22,7 +22,10 @@ import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendActivity;
|
||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
@@ -33,8 +36,10 @@ import com.google.android.maps.MapController;
|
||||
import com.google.android.maps.MapView;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.Intent;
|
||||
import android.location.Location;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
@@ -51,6 +56,7 @@ import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
@@ -121,7 +127,7 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
// ------------------------
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
protected void onCreate(Bundle bundle) {
|
||||
Log.d(TAG, "MapActivity.onCreate");
|
||||
super.onCreate(bundle);
|
||||
|
||||
@@ -130,8 +136,6 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
new StatusAnnouncerFactory(ApiFeatures.getInstance()).getVolumeStream();
|
||||
setVolumeControlStream(volumeStream);
|
||||
|
||||
dataHub = MyTracks.getInstance().getDataHub();
|
||||
|
||||
// We don't need a window title bar:
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
||||
@@ -178,9 +182,10 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
Log.d(TAG, "MapActivity.onStart");
|
||||
Log.d(TAG, "MapActivity.onResume");
|
||||
super.onResume();
|
||||
|
||||
dataHub = TrackDataHub.getStartedInstance();
|
||||
dataHub.registerTrackDataListener(this, EnumSet.of(
|
||||
ListenerDataType.SELECTED_TRACK_CHANGED,
|
||||
ListenerDataType.POINT_UPDATES,
|
||||
@@ -201,9 +206,10 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
Log.d(TAG, "MapActivity.onStop");
|
||||
Log.d(TAG, "MapActivity.onPause");
|
||||
|
||||
dataHub.unregisterTrackDataListener(this);
|
||||
dataHub = null;
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
@@ -336,9 +342,9 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
|
||||
if (trackSelected) {
|
||||
busyPane.setVisibility(View.VISIBLE);
|
||||
|
||||
|
||||
zoomMapToBoundaries(track);
|
||||
|
||||
|
||||
mapOverlay.setShowEndMarker(!isRecording);
|
||||
busyPane.setVisibility(View.GONE);
|
||||
}
|
||||
@@ -391,13 +397,44 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
if (!super.onMenuItemSelected(featureId, item)) {
|
||||
MyTracks.getInstance().onActivityResult(
|
||||
Constants.getActionFromMenuId(item.getItemId()), RESULT_OK,
|
||||
new Intent());
|
||||
return true;
|
||||
switch (item.getItemId()) {
|
||||
case Constants.MENU_SEND_TO_GOOGLE:
|
||||
SendActivity.sendToGoogle(this, dataHub.getSelectedTrackId(), false);
|
||||
return true;
|
||||
case Constants.MENU_SHARE_LINK:
|
||||
SendActivity.sendToGoogle(this, dataHub.getSelectedTrackId(), true);
|
||||
return true;
|
||||
case Constants.MENU_SAVE_GPX_FILE:
|
||||
case Constants.MENU_SAVE_KML_FILE:
|
||||
case Constants.MENU_SAVE_CSV_FILE:
|
||||
case Constants.MENU_SAVE_TCX_FILE:
|
||||
case Constants.MENU_SHARE_GPX_FILE:
|
||||
case Constants.MENU_SHARE_KML_FILE:
|
||||
case Constants.MENU_SHARE_CSV_FILE:
|
||||
case Constants.MENU_SHARE_TCX_FILE:
|
||||
SaveActivity.handleExportTrackAction(this, dataHub.getSelectedTrackId(),
|
||||
Constants.getActionFromMenuId(item.getItemId()));
|
||||
return true;
|
||||
case Constants.MENU_EDIT: {
|
||||
Intent intent = new Intent(this, TrackDetails.class);
|
||||
// TODO: Pass in a content URI
|
||||
intent.putExtra("trackid", dataHub.getSelectedTrackId());
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
case Constants.MENU_DELETE: {
|
||||
Uri uri = ContentUris.withAppendedId(
|
||||
TracksColumns.CONTENT_URI, dataHub.getSelectedTrackId());
|
||||
Intent intent = new Intent(Intent.ACTION_DELETE, uri);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
case Constants.MENU_CLEAR_MAP:
|
||||
dataHub.unloadCurrentTrack();
|
||||
return true;
|
||||
default:
|
||||
return super.onMenuItemSelected(featureId, item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -464,21 +501,21 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
@Override
|
||||
public void onProviderStateChange(ProviderState state) {
|
||||
final int messageId;
|
||||
final boolean bindClick;
|
||||
final boolean isGpsDisabled;
|
||||
switch (state) {
|
||||
case DISABLED:
|
||||
messageId = R.string.status_enable_gps;
|
||||
bindClick = true;
|
||||
isGpsDisabled = true;
|
||||
break;
|
||||
case NO_FIX:
|
||||
case BAD_FIX:
|
||||
messageId = R.string.wait_for_fix;
|
||||
bindClick = false;
|
||||
isGpsDisabled = false;
|
||||
break;
|
||||
case GOOD_FIX:
|
||||
// Nothing to show.
|
||||
messageId = -1;
|
||||
bindClick = false;
|
||||
isGpsDisabled = false;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected state: " + state);
|
||||
@@ -491,7 +528,13 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
messageText.setText(messageId);
|
||||
messagePane.setVisibility(View.VISIBLE);
|
||||
|
||||
if (bindClick) {
|
||||
if (isGpsDisabled) {
|
||||
// Give a warning about this state.
|
||||
Toast.makeText(MapActivity.this,
|
||||
R.string.error_no_gps_location_provider,
|
||||
Toast.LENGTH_LONG).show();
|
||||
|
||||
// Make clicking take the user to the location settings.
|
||||
messagePane.setOnClickListener(MapActivity.this);
|
||||
} else {
|
||||
messagePane.setOnClickListener(null);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||
import com.google.android.maps.GeoPoint;
|
||||
@@ -33,6 +35,7 @@ import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.location.Location;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -71,7 +74,7 @@ public class MapOverlay extends Overlay {
|
||||
private GeoPoint lastReferencePoint;
|
||||
private Rect lastViewRect;
|
||||
private Path lastPath;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a pre-processed {@code Location} to speed up drawing.
|
||||
* This class is more like a data object and doesn't provide accessors.
|
||||
@@ -93,13 +96,13 @@ public class MapOverlay extends Overlay {
|
||||
*/
|
||||
public CachedLocation(Location location) {
|
||||
this.valid = LocationUtils.isValidLocation(location);
|
||||
this.geoPoint = valid ? LocationUtils.getGeoPoint(location) : null;
|
||||
this.geoPoint = valid ? LocationUtils.getGeoPoint(location) : null;
|
||||
}
|
||||
};
|
||||
|
||||
public MapOverlay(Context context) {
|
||||
this.context = context;
|
||||
|
||||
|
||||
this.waypoints = new ArrayList<Waypoint>();
|
||||
this.points = new ArrayList<CachedLocation>(1024);
|
||||
this.pendingPoints = new ArrayBlockingQueue<CachedLocation>(
|
||||
@@ -164,7 +167,7 @@ public class MapOverlay extends Overlay {
|
||||
|
||||
/**
|
||||
* Add a location to the map overlay.
|
||||
*
|
||||
*
|
||||
* NOTE: This method doesn't take ownership of the given location, so it is
|
||||
* safe to reuse the same location while calling this method.
|
||||
*
|
||||
@@ -172,14 +175,18 @@ public class MapOverlay extends Overlay {
|
||||
*/
|
||||
public void addLocation(Location l) {
|
||||
// Queue up in the pending queue until it's merged with {@code #points}.
|
||||
pendingPoints.offer(new CachedLocation(l));
|
||||
if (!pendingPoints.offer(new CachedLocation(l))) {
|
||||
Log.e(TAG, "Unable to add pending points");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a segment split to the map overlay.
|
||||
*/
|
||||
public void addSegmentSplit() {
|
||||
pendingPoints.offer(new CachedLocation());
|
||||
if (!pendingPoints.offer(new CachedLocation())) {
|
||||
Log.e(TAG, "Unable to add pending points");
|
||||
}
|
||||
}
|
||||
|
||||
public void addWaypoint(Waypoint wpt) {
|
||||
@@ -203,7 +210,7 @@ public class MapOverlay extends Overlay {
|
||||
return waypoints.size();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void clearPoints() {
|
||||
synchronized (points) {
|
||||
points.clear();
|
||||
@@ -235,10 +242,15 @@ public class MapOverlay extends Overlay {
|
||||
|
||||
// It's safe to keep projection within a single draw operation.
|
||||
final Projection projection = getMapProjection(mapView);
|
||||
if (projection == null) {
|
||||
Log.w(TAG, "No projection, unable to draw");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current viewing window.
|
||||
if (trackDrawingEnabled) {
|
||||
Rect viewRect = getMapViewRect(mapView);
|
||||
|
||||
|
||||
// Draw the selected track:
|
||||
drawTrack(canvas, projection, viewRect);
|
||||
|
||||
@@ -249,12 +261,12 @@ public class MapOverlay extends Overlay {
|
||||
// Draw the current location
|
||||
drawMyLocation(canvas, projection);
|
||||
}
|
||||
|
||||
|
||||
// Visible for testing.
|
||||
Projection getMapProjection(MapView mapView) {
|
||||
return mapView.getProjection();
|
||||
}
|
||||
|
||||
|
||||
// Visible for testing.
|
||||
Rect getMapViewRect(MapView mapView) {
|
||||
int w = mapView.getLongitudeSpan();
|
||||
@@ -263,12 +275,12 @@ public class MapOverlay extends Overlay {
|
||||
int cy = mapView.getMapCenter().getLatitudeE6();
|
||||
return new Rect(cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2);
|
||||
}
|
||||
|
||||
|
||||
// Visible for testing.
|
||||
Path newPath() {
|
||||
return new Path();
|
||||
}
|
||||
|
||||
|
||||
// Visible for testing.
|
||||
Path getLastPath() {
|
||||
return lastPath;
|
||||
@@ -304,9 +316,9 @@ public class MapOverlay extends Overlay {
|
||||
synchronized (points) {
|
||||
// Merge the pending points with the list of cached locations.
|
||||
final GeoPoint referencePoint = projection.fromPixels(0, 0);
|
||||
int newPoints = pendingPoints.drainTo(points);
|
||||
int newPoints = pendingPoints.drainTo(points);
|
||||
boolean newProjection = !viewRect.equals(lastViewRect) ||
|
||||
!referencePoint.equals(lastReferencePoint);
|
||||
!referencePoint.equals(lastReferencePoint);
|
||||
if (newPoints == 0 && lastPath != null && !newProjection) {
|
||||
// No need to recreate path (same points and viewing area).
|
||||
path = lastPath;
|
||||
@@ -318,12 +330,12 @@ public class MapOverlay extends Overlay {
|
||||
} else if (lastPath != null && !newProjection) {
|
||||
// Incremental update of the path, without repositioning the view.
|
||||
path = lastPath;
|
||||
updatePath(projection, viewRect, path, numPoints - newPoints);
|
||||
updatePath(projection, viewRect, path, numPoints - newPoints);
|
||||
} else {
|
||||
// The view has changed so we have to start from scratch.
|
||||
path = newPath();
|
||||
path.incReserve(numPoints);
|
||||
updatePath(projection, viewRect, path, 0);
|
||||
updatePath(projection, viewRect, path, 0);
|
||||
}
|
||||
lastPath = path;
|
||||
}
|
||||
@@ -344,7 +356,7 @@ public class MapOverlay extends Overlay {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Draw the "Start" marker.
|
||||
for (int i = 0; i < points.size(); ++i) {
|
||||
if (points.get(i).valid) {
|
||||
@@ -354,7 +366,7 @@ public class MapOverlay extends Overlay {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void updatePath(Projection projection, Rect viewRect, Path path,
|
||||
int startLocationIdx) {
|
||||
// Whether to start a new segment on new valid and visible point.
|
||||
@@ -370,7 +382,7 @@ public class MapOverlay extends Overlay {
|
||||
newSegment = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
final GeoPoint geoPoint = loc.geoPoint;
|
||||
// Check if this breaks the existing segment.
|
||||
boolean visible = alwaysVisible || viewRect.contains(
|
||||
@@ -380,7 +392,7 @@ public class MapOverlay extends Overlay {
|
||||
newSegment = true;
|
||||
}
|
||||
lastVisible = visible;
|
||||
|
||||
|
||||
// Either move to beginning of a new segment or continue the old one.
|
||||
projection.toPixels(geoPoint, pt);
|
||||
if (newSegment) {
|
||||
@@ -391,7 +403,7 @@ public class MapOverlay extends Overlay {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Visible for testing.
|
||||
Point drawElement(Canvas canvas, Projection projection, GeoPoint geoPoint,
|
||||
Drawable element, int offsetX, int offsetY) {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -24,7 +24,7 @@ import android.view.MenuItem;
|
||||
|
||||
/**
|
||||
* Manage the application menus.
|
||||
*
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
class MenuManager {
|
||||
@@ -34,7 +34,7 @@ class MenuManager {
|
||||
public MenuManager(MyTracks activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
activity.getMenuInflater().inflate(R.menu.main, menu);
|
||||
return true;
|
||||
@@ -52,7 +52,7 @@ class MenuManager {
|
||||
.setEnabled(isRecording)
|
||||
.setVisible(isRecording);
|
||||
}
|
||||
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_start_recording: {
|
||||
@@ -86,10 +86,6 @@ class MenuManager {
|
||||
case R.id.menu_help: {
|
||||
return startActivity(WelcomeActivity.class);
|
||||
}
|
||||
case Constants.MENU_CLEAR_MAP: {
|
||||
activity.clearSelectedTrack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import com.google.android.accounts.Account;
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.io.AuthManager;
|
||||
import com.google.android.apps.mytracks.io.AuthManager.AuthCallback;
|
||||
import com.google.android.apps.mytracks.io.AuthManagerFactory;
|
||||
import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
|
||||
import com.google.android.apps.mytracks.io.mymaps.MyMapsConstants;
|
||||
@@ -25,11 +27,8 @@ import com.google.android.maps.mytracks.R;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.MenuItem;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.View.OnCreateContextMenuListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ListView;
|
||||
@@ -42,29 +41,15 @@ import android.widget.TextView;
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class MyMapsList extends Activity implements MapsFacade.MapsListCallback {
|
||||
private static final int MENU_OPEN = 0;
|
||||
private static final int MENU_SHARE = 2;
|
||||
private static final int GET_LOGIN = 1;
|
||||
|
||||
public static final String EXTRA_ACCOUNT_NAME = "accountName";
|
||||
public static final String EXTRA_ACCOUNT_TYPE = "accountType";
|
||||
|
||||
private MapsFacade mapsClient;
|
||||
private AuthManager auth;
|
||||
private MyMapsListAdapter listAdapter;
|
||||
|
||||
private int contextPosition;
|
||||
|
||||
private final OnCreateContextMenuListener contextMenuListener =
|
||||
new OnCreateContextMenuListener() {
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
AdapterView.AdapterContextMenuInfo info =
|
||||
(AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
contextPosition = info.position;
|
||||
menu.add(0, MENU_OPEN, 0, R.string.open_map);
|
||||
menu.add(0, MENU_SHARE, 0, R.string.share_map);
|
||||
}
|
||||
};
|
||||
|
||||
private final OnItemClickListener clickListener =
|
||||
new OnItemClickListener() {
|
||||
@Override
|
||||
@@ -91,7 +76,6 @@ public class MyMapsList extends Activity implements MapsFacade.MapsListCallback
|
||||
|
||||
ListView list = (ListView) findViewById(R.id.maplist);
|
||||
list.setOnItemClickListener(clickListener);
|
||||
list.setOnCreateContextMenuListener(contextMenuListener);
|
||||
list.setAdapter(listAdapter);
|
||||
|
||||
startLogin();
|
||||
@@ -101,28 +85,33 @@ public class MyMapsList extends Activity implements MapsFacade.MapsListCallback
|
||||
// Starts in the UI thread.
|
||||
// TODO fix this for non-froyo devices.
|
||||
if (AuthManagerFactory.useModernAuthManager()) {
|
||||
MyTracks.getInstance().getAccountChooser().chooseAccount(
|
||||
MyMapsList.this,
|
||||
new AccountChooser.AccountHandler() {
|
||||
@Override
|
||||
public void handleAccountSelected(Account account) {
|
||||
// Account selection happens in the UI thread.
|
||||
if (account != null) {
|
||||
// The user did not quit and there was a valid google
|
||||
// account.
|
||||
doLogin(account);
|
||||
}
|
||||
}
|
||||
});
|
||||
Intent intent = getIntent();
|
||||
String accountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME);
|
||||
String accountType = intent.getStringExtra(EXTRA_ACCOUNT_TYPE);
|
||||
if (accountName == null || accountType == null) {
|
||||
Log.e(TAG, "Didn't receive account name or type");
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
doLogin(auth.getAccountObject(accountName, accountType));
|
||||
} else {
|
||||
doLogin(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void doLogin(final Account account) {
|
||||
private void doLogin(final Object account) {
|
||||
// Starts in the UI thread.
|
||||
auth.doLogin(new Runnable() {
|
||||
public void run() {
|
||||
auth.doLogin(new AuthCallback() {
|
||||
@Override
|
||||
public void onAuthResult(boolean success) {
|
||||
if (!success) {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// Runs in UI thread.
|
||||
mapsClient = new MapsFacade(MyMapsList.this, auth);
|
||||
|
||||
@@ -183,27 +172,4 @@ public class MyMapsList extends Activity implements MapsFacade.MapsListCallback
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_OPEN:
|
||||
clickListener.onItemClick(null, null, contextPosition, 0);
|
||||
return true;
|
||||
case MENU_SHARE:
|
||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||
shareIntent.setType("text/plain");
|
||||
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
|
||||
getText(R.string.share_map_subject));
|
||||
String[] listItem = (String[]) listAdapter.getMapListingArray(contextPosition);
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT, String.format(
|
||||
getText(R.string.share_map_body_format).toString(),
|
||||
listItem[1],
|
||||
MapsFacade.buildMapUrl(listItem[0])));
|
||||
startActivity(Intent.createChooser(shareIntent,
|
||||
getText(R.string.share_map).toString()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,8 +16,10 @@
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||
import com.google.android.apps.mytracks.services.sensors.SensorUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
@@ -57,6 +59,11 @@ public class SensorStateActivity extends Activity {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Connection to the recording service.
|
||||
*/
|
||||
private TrackRecordingServiceConnection serviceConnection;
|
||||
|
||||
/**
|
||||
* A task which will update the U/I.
|
||||
*/
|
||||
@@ -79,35 +86,45 @@ public class SensorStateActivity extends Activity {
|
||||
|
||||
setContentView(R.layout.sensor_state);
|
||||
|
||||
// TODO: Allow reading from sensors even if service is not running.
|
||||
serviceConnection = new TrackRecordingServiceConnection(this, stateUpdater);
|
||||
serviceConnection.bindIfRunning();
|
||||
updateState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
serviceConnection.bindIfRunning();
|
||||
|
||||
timer = new Timer();
|
||||
timer.schedule(new RefreshTask(), REFRESH_PERIOD_MS, REFRESH_PERIOD_MS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
timer = null;
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
serviceConnection.unbind();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
protected void updateState() {
|
||||
MyTracks mt = MyTracks.getInstance();
|
||||
|
||||
ITrackRecordingService service =
|
||||
mt == null ? null : mt.getTrackRecordingService();
|
||||
ITrackRecordingService service = serviceConnection.getServiceIfBound();
|
||||
if (service == null) {
|
||||
Log.d(Constants.TAG, "Could not get track recording service.");
|
||||
updateSensorState(Sensor.SensorState.NONE);
|
||||
updateSensorData(null);
|
||||
return;
|
||||
}
|
||||
|
||||
Sensor.SensorDataSet sds = null;
|
||||
try {
|
||||
byte[] buff = service.getSensorData();
|
||||
@@ -153,8 +170,8 @@ public class SensorStateActivity extends Activity {
|
||||
|
||||
if (sds.hasPower() && sds.getPower().hasValue()
|
||||
&& sds.getPower().getState() == Sensor.SensorState.SENDING) {
|
||||
utils.setText(R.id.power_state_register,
|
||||
Integer.toString(sds.getPower().getValue()));
|
||||
utils.setText(R.id.power_state_register,
|
||||
Integer.toString(sds.getPower().getValue()));
|
||||
} else {
|
||||
utils.setText(R.id.power_state_register,
|
||||
SensorUtils.getStateAsString(
|
||||
@@ -180,14 +197,14 @@ public class SensorStateActivity extends Activity {
|
||||
if (sds.hasHeartRate() && sds.getHeartRate().hasValue()
|
||||
&& sds.getHeartRate().getState() == Sensor.SensorState.SENDING) {
|
||||
utils.setText(R.id.heart_rate_register,
|
||||
Integer.toString(sds.getHeartRate().getValue()));
|
||||
Integer.toString(sds.getHeartRate().getValue()));
|
||||
} else {
|
||||
utils.setText(R.id.heart_rate_register,
|
||||
SensorUtils.getStateAsString(
|
||||
sds.hasHeartRate()
|
||||
? sds.getHeartRate().getState()
|
||||
: Sensor.SensorState.NONE,
|
||||
this));
|
||||
utils.setText(R.id.heart_rate_register,
|
||||
SensorUtils.getStateAsString(
|
||||
sds.hasHeartRate()
|
||||
? sds.getHeartRate().getState()
|
||||
: Sensor.SensorState.NONE,
|
||||
this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,8 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
|
||||
private void updateSensorSettings(String sensorType) {
|
||||
boolean usesBluetooth =
|
||||
getString(R.string.zephyr_sensor_type).equals(sensorType);
|
||||
getString(R.string.zephyr_sensor_type).equals(sensorType)
|
||||
|| getString(R.string.polar_sensor_type).equals(sensorType);
|
||||
findPreference(
|
||||
getString(R.string.bluetooth_sensor_key)).setEnabled(usesBluetooth);
|
||||
findPreference(
|
||||
@@ -339,7 +340,7 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
.setPositiveButton(android.R.string.ok,
|
||||
new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int button) {
|
||||
public void onClick(DialogInterface dialogInterface, int button) {
|
||||
onResetPreferencesConfirmed();
|
||||
}
|
||||
})
|
||||
|
||||
@@ -22,11 +22,13 @@ import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.services.ServiceUtils;
|
||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
@@ -46,6 +48,18 @@ import java.util.EnumSet;
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class StatsActivity extends Activity implements TrackDataListener {
|
||||
/**
|
||||
* A runnable for posting to the UI thread. Will update the total time field.
|
||||
*/
|
||||
private final Runnable updateResults = new Runnable() {
|
||||
public void run() {
|
||||
if (dataHub != null && dataHub.isRecordingSelected()) {
|
||||
utils.setTime(R.id.total_time_register,
|
||||
System.currentTimeMillis() - startTime);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private StatsUtilities utils;
|
||||
private UIUpdateThread thread;
|
||||
|
||||
@@ -61,18 +75,7 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
||||
private boolean showCurrentSegment = false;
|
||||
|
||||
private TrackDataHub dataHub;
|
||||
|
||||
/**
|
||||
* A runnable for posting to the UI thread. Will update the total time field.
|
||||
*/
|
||||
private final Runnable updateResults = new Runnable() {
|
||||
public void run() {
|
||||
if (dataHub.isRecordingSelected()) {
|
||||
utils.setTime(R.id.total_time_register,
|
||||
System.currentTimeMillis() - startTime);
|
||||
}
|
||||
}
|
||||
};
|
||||
private SharedPreferences preferences;
|
||||
|
||||
/**
|
||||
* A thread that updates the total time field every second.
|
||||
@@ -87,7 +90,7 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(TAG, "Started UI update thread");
|
||||
while (MyTracks.getInstance().isRecording()) {
|
||||
while (ServiceUtils.isRecording(StatsActivity.this, null, preferences)) {
|
||||
runOnUiThread(updateResults);
|
||||
try {
|
||||
Thread.sleep(1000L);
|
||||
@@ -102,10 +105,10 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
dataHub = MyTracks.getInstance().getDataHub();
|
||||
preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||
utils = new StatsUtilities(this);
|
||||
|
||||
// The volume we want to control is the Text-To-Speech volume
|
||||
@@ -132,18 +135,20 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
dataHub = TrackDataHub.getStartedInstance();
|
||||
dataHub.registerTrackDataListener(this, EnumSet.of(
|
||||
ListenerDataType.SELECTED_TRACK_CHANGED,
|
||||
ListenerDataType.TRACK_UPDATES,
|
||||
ListenerDataType.LOCATION_UPDATES,
|
||||
ListenerDataType.DISPLAY_PREFERENCES));
|
||||
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
dataHub.unregisterTrackDataListener(this);
|
||||
dataHub = null;
|
||||
|
||||
if (thread != null) {
|
||||
thread.interrupt();
|
||||
@@ -171,7 +176,7 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
||||
|
||||
utils.setReportSpeed(displaySpeed);
|
||||
updateLabels();
|
||||
|
||||
|
||||
return true; // Reload data
|
||||
}
|
||||
|
||||
@@ -260,7 +265,8 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
||||
|
||||
@Override
|
||||
public void onCurrentLocationChanged(final Location loc) {
|
||||
if (dataHub.isRecordingSelected()) {
|
||||
TrackDataHub localDataHub = dataHub;
|
||||
if (localDataHub != null && localDataHub.isRecordingSelected()) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -296,6 +302,8 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
||||
|
||||
@Override
|
||||
public void onTrackUpdated(final Track track) {
|
||||
TrackDataHub localDataHub = dataHub;
|
||||
final boolean recordingSelected = localDataHub != null && localDataHub.isRecordingSelected();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -305,7 +313,7 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
||||
}
|
||||
|
||||
startTime = track.getStatistics().getStartTime();
|
||||
if (!dataHub.isRecordingSelected()) {
|
||||
if (!recordingSelected) {
|
||||
utils.setTime(R.id.total_time_register,
|
||||
track.getStatistics().getTotalTime());
|
||||
showUnknownLocation();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -15,17 +15,26 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendActivity;
|
||||
import com.google.android.apps.mytracks.services.ServiceUtils;
|
||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.MenuItem;
|
||||
@@ -76,8 +85,7 @@ public class TrackList extends ListActivity
|
||||
R.string.tracklist_show_track);
|
||||
menu.add(0, Constants.MENU_EDIT, 0,
|
||||
R.string.tracklist_edit_track);
|
||||
if (!MyTracks.getInstance().isRecording()
|
||||
|| trackId != recordingTrackId) {
|
||||
if (!isRecording() || trackId != recordingTrackId) {
|
||||
menu.add(0, Constants.MENU_SEND_TO_GOOGLE, 0,
|
||||
R.string.tracklist_send_to_google);
|
||||
SubMenu share = menu.addSubMenu(0, Constants.MENU_SHARE, 0,
|
||||
@@ -109,6 +117,16 @@ public class TrackList extends ListActivity
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable serviceBindingChanged = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateButtonsEnabled();
|
||||
}
|
||||
};
|
||||
|
||||
private TrackRecordingServiceConnection serviceConnection;
|
||||
private SharedPreferences preferences;
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(
|
||||
SharedPreferences sharedPreferences, String key) {
|
||||
@@ -138,32 +156,48 @@ public class TrackList extends ListActivity
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
if (!super.onMenuItemSelected(featureId, item)) {
|
||||
switch (item.getItemId()) {
|
||||
case Constants.MENU_SHOW: {
|
||||
onListItemClick(null, null, 0, trackId);
|
||||
return true;
|
||||
}
|
||||
case Constants.MENU_EDIT: {
|
||||
Intent intent = new Intent(this, TrackDetails.class);
|
||||
intent.putExtra("trackid", trackId);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
case Constants.MENU_SHARE:
|
||||
case Constants.MENU_WRITE_TO_SD_CARD:
|
||||
return false;
|
||||
default: {
|
||||
Intent result = new Intent();
|
||||
result.putExtra("trackid", trackId);
|
||||
setResult(
|
||||
Constants.getActionFromMenuId(item.getItemId()), result);
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
switch (item.getItemId()) {
|
||||
case Constants.MENU_SHOW: {
|
||||
onListItemClick(null, null, 0, trackId);
|
||||
return true;
|
||||
}
|
||||
case Constants.MENU_EDIT: {
|
||||
Intent intent = new Intent(this, TrackDetails.class);
|
||||
intent.putExtra("trackid", trackId);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
case Constants.MENU_SHARE:
|
||||
case Constants.MENU_WRITE_TO_SD_CARD:
|
||||
return false;
|
||||
case Constants.MENU_SEND_TO_GOOGLE:
|
||||
SendActivity.sendToGoogle(this, trackId, false);
|
||||
return true;
|
||||
case Constants.MENU_SHARE_LINK:
|
||||
SendActivity.sendToGoogle(this, trackId, true);
|
||||
return true;
|
||||
case Constants.MENU_SAVE_GPX_FILE:
|
||||
case Constants.MENU_SAVE_KML_FILE:
|
||||
case Constants.MENU_SAVE_CSV_FILE:
|
||||
case Constants.MENU_SAVE_TCX_FILE:
|
||||
case Constants.MENU_SHARE_GPX_FILE:
|
||||
case Constants.MENU_SHARE_KML_FILE:
|
||||
case Constants.MENU_SHARE_CSV_FILE:
|
||||
case Constants.MENU_SHARE_TCX_FILE:
|
||||
SaveActivity.handleExportTrackAction(this, trackId,
|
||||
Constants.getActionFromMenuId(item.getItemId()));
|
||||
return true;
|
||||
case Constants.MENU_DELETE: {
|
||||
Intent intent = new Intent(Intent.ACTION_DELETE);
|
||||
Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
|
||||
intent.setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
Log.w(TAG, "Unknown menu item: " + item.getItemId() + "(" + item.getTitle() + ")");
|
||||
return super.onMenuItemSelected(featureId, item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,17 +231,19 @@ public class TrackList extends ListActivity
|
||||
listView = getListView();
|
||||
listView.setOnCreateContextMenuListener(contextMenuListener);
|
||||
|
||||
preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||
serviceConnection = new TrackRecordingServiceConnection(this, serviceBindingChanged);
|
||||
|
||||
View deleteAll = findViewById(R.id.tracklist_btn_delete_all);
|
||||
View exportAll = findViewById(R.id.tracklist_btn_export_all);
|
||||
boolean notRecording = !MyTracks.getInstance().isRecording();
|
||||
deleteAll.setOnClickListener(this);
|
||||
deleteAll.setEnabled(notRecording);
|
||||
|
||||
View exportAll = findViewById(R.id.tracklist_btn_export_all);
|
||||
exportAll.setOnClickListener(this);
|
||||
exportAll.setEnabled(notRecording);
|
||||
|
||||
updateButtonsEnabled();
|
||||
|
||||
findViewById(R.id.tracklist_btn_import_all).setOnClickListener(this);
|
||||
|
||||
SharedPreferences preferences =
|
||||
getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
metricUnits =
|
||||
preferences.getBoolean(getString(R.string.metric_units_key), true);
|
||||
@@ -220,6 +256,29 @@ public class TrackList extends ListActivity
|
||||
setListAdapter();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
|
||||
serviceConnection.bindIfRunning();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
serviceConnection.unbind();
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private void updateButtonsEnabled() {
|
||||
View deleteAll = findViewById(R.id.tracklist_btn_delete_all);
|
||||
View exportAll = findViewById(R.id.tracklist_btn_export_all);
|
||||
|
||||
boolean notRecording = !isRecording();
|
||||
deleteAll.setEnabled(notRecording);
|
||||
exportAll.setEnabled(notRecording);
|
||||
}
|
||||
|
||||
private void setListAdapter() {
|
||||
// Get a cursor with all tracks
|
||||
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
|
||||
@@ -283,4 +342,8 @@ public class TrackList extends ListActivity
|
||||
});
|
||||
setListAdapter(adapter);
|
||||
}
|
||||
|
||||
private boolean isRecording() {
|
||||
return ServiceUtils.isRecording(TrackList.this, serviceConnection.getServiceIfBound(), preferences);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2009 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -15,10 +15,14 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
|
||||
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
@@ -43,6 +47,7 @@ import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.SimpleCursorAdapter;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* Activity which shows the list of waypoints in a track.
|
||||
@@ -54,12 +59,13 @@ public class WaypointsList extends ListActivity
|
||||
|
||||
private int contextPosition = -1;
|
||||
private long trackId = -1;
|
||||
private long waypointId = -1;
|
||||
private long selectedWaypointId = -1;
|
||||
private ListView listView = null;
|
||||
private Button insertWaypointButton = null;
|
||||
private Button insertStatisticsButton = null;
|
||||
private long recordingTrackId = -1;
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
private TrackRecordingServiceConnection serviceConnection;
|
||||
|
||||
private Cursor waypointsCursor = null;
|
||||
|
||||
@@ -71,27 +77,26 @@ public class WaypointsList extends ListActivity
|
||||
AdapterView.AdapterContextMenuInfo info =
|
||||
(AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
contextPosition = info.position;
|
||||
waypointId = WaypointsList.this.listView.getAdapter()
|
||||
selectedWaypointId = WaypointsList.this.listView.getAdapter()
|
||||
.getItemId(contextPosition);
|
||||
int type = providerUtils.getWaypoint(info.id).getType();
|
||||
menu.add(0, Constants.MENU_SHOW, 0,
|
||||
R.string.waypointslist_show_waypoint);
|
||||
menu.add(0, Constants.MENU_EDIT, 0,
|
||||
R.string.waypointslist_edit_waypoint);
|
||||
menu.add(0, Constants.MENU_DELETE, 0,
|
||||
R.string.waypointslist_delete_waypoint).setEnabled(
|
||||
recordingTrackId < 0 || type == Waypoint.TYPE_WAYPOINT ||
|
||||
info.id != providerUtils.getLastWaypointId(recordingTrackId));
|
||||
Waypoint waypoint = providerUtils.getWaypoint(info.id);
|
||||
if (waypoint != null) {
|
||||
int type = waypoint.getType();
|
||||
menu.add(0, Constants.MENU_SHOW, 0,
|
||||
R.string.waypointslist_show_waypoint);
|
||||
menu.add(0, Constants.MENU_EDIT, 0,
|
||||
R.string.waypointslist_edit_waypoint);
|
||||
menu.add(0, Constants.MENU_DELETE, 0,
|
||||
R.string.waypointslist_delete_waypoint).setEnabled(
|
||||
recordingTrackId < 0 || type == Waypoint.TYPE_WAYPOINT ||
|
||||
info.id != providerUtils.getLastWaypointId(recordingTrackId));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||
Intent result = new Intent();
|
||||
result.putExtra("trackid", trackId);
|
||||
result.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, id);
|
||||
setResult(Constants.EDIT_WAYPOINT, result);
|
||||
finish();
|
||||
editWaypoint(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -99,29 +104,38 @@ public class WaypointsList extends ListActivity
|
||||
if (!super.onMenuItemSelected(featureId, item)) {
|
||||
switch (item.getItemId()) {
|
||||
case Constants.MENU_SHOW: {
|
||||
onListItemClick(null, null, 0, waypointId);
|
||||
Intent result = new Intent();
|
||||
result.putExtra("trackid", trackId);
|
||||
result.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, selectedWaypointId);
|
||||
setResult(RESULT_OK, result);
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
case Constants.MENU_EDIT: {
|
||||
Intent intent = new Intent(this, WaypointDetails.class);
|
||||
intent.putExtra("trackid", trackId);
|
||||
intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, waypointId);
|
||||
startActivity(intent);
|
||||
editWaypoint(selectedWaypointId);
|
||||
return true;
|
||||
}
|
||||
case Constants.MENU_DELETE: {
|
||||
deleteWaypoint(waypointId);
|
||||
deleteWaypoint(selectedWaypointId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void editWaypoint(long waypointId) {
|
||||
Intent intent = new Intent(this, WaypointDetails.class);
|
||||
intent.putExtra("trackid", trackId);
|
||||
intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, waypointId);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
||||
serviceConnection = new TrackRecordingServiceConnection(this, null);
|
||||
|
||||
// We don't need a window title bar:
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
@@ -159,7 +173,7 @@ public class WaypointsList extends ListActivity
|
||||
trackId = -1;
|
||||
}
|
||||
|
||||
final long firstWaypointId = providerUtils.getFirstWaypointId(trackId);
|
||||
final long firstWaypointId = providerUtils.getFirstWaypointId(trackId);
|
||||
waypointsCursor = getContentResolver().query(
|
||||
WaypointsColumns.CONTENT_URI, null,
|
||||
WaypointsColumns.TRACKID + "=" + trackId + " AND "
|
||||
@@ -168,6 +182,20 @@ public class WaypointsList extends ListActivity
|
||||
setListAdapter();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
serviceConnection.bindIfRunning();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
serviceConnection.unbind();
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
WaypointCreationRequest request;
|
||||
@@ -181,17 +209,10 @@ public class WaypointsList extends ListActivity
|
||||
default:
|
||||
return;
|
||||
}
|
||||
long id;
|
||||
try {
|
||||
id = MyTracks.getInstance().insertWaypoint(request);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(Constants.TAG, "Cannot insert marker.", e);
|
||||
return;
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(Constants.TAG, "Cannot insert marker.", e);
|
||||
return;
|
||||
}
|
||||
long id = insertWaypoint(request);
|
||||
if (id < 0) {
|
||||
Toast.makeText(this, R.string.error_unable_to_insert_marker,
|
||||
Toast.LENGTH_LONG).show();
|
||||
Log.e(Constants.TAG, "Failed to insert marker.");
|
||||
return;
|
||||
}
|
||||
@@ -200,6 +221,28 @@ public class WaypointsList extends ListActivity
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private long insertWaypoint(WaypointCreationRequest request) {
|
||||
try {
|
||||
ITrackRecordingService trackRecordingService = serviceConnection.getServiceIfBound();
|
||||
if (trackRecordingService != null) {
|
||||
long waypointId = trackRecordingService.insertWaypoint(request);
|
||||
if (waypointId >= 0) {
|
||||
Toast.makeText(this, R.string.status_statistics_inserted,
|
||||
Toast.LENGTH_LONG).show();
|
||||
return waypointId;
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Not connected to service, not inserting waypoint");
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(Constants.TAG, "Cannot insert marker.", e);
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(Constants.TAG, "Cannot insert marker.", e);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void setListAdapter() {
|
||||
// Get a cursor with all tracks
|
||||
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
|
||||
@@ -209,7 +252,7 @@ public class WaypointsList extends ListActivity
|
||||
new String[] { WaypointsColumns.NAME, WaypointsColumns.TIME,
|
||||
WaypointsColumns.CATEGORY, WaypointsColumns.TYPE },
|
||||
new int[] { R.id.waypointslist_item_name,
|
||||
R.id.waypointslist_item_time,
|
||||
R.id.waypointslist_item_time,
|
||||
R.id.waypointslist_item_category,
|
||||
R.id.waypointslist_item_icon });
|
||||
|
||||
@@ -219,7 +262,7 @@ public class WaypointsList extends ListActivity
|
||||
waypointsCursor.getColumnIndexOrThrow(WaypointsColumns.TYPE);
|
||||
adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
|
||||
@Override
|
||||
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
|
||||
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
|
||||
if (columnIndex == timeIdx) {
|
||||
long time = cursor.getLong(timeIdx);
|
||||
TextView textView = (TextView) view;
|
||||
@@ -258,8 +301,8 @@ public class WaypointsList extends ListActivity
|
||||
builder.setPositiveButton(getString(R.string.yes),
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int i) {
|
||||
dialog.dismiss();
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
dialogInterface.dismiss();
|
||||
providerUtils.deleteWaypoint(waypointId,
|
||||
new StringUtils(WaypointsList.this));
|
||||
}
|
||||
@@ -267,8 +310,8 @@ public class WaypointsList extends ListActivity
|
||||
builder.setNegativeButton(getString(R.string.no),
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int i) {
|
||||
dialog.dismiss();
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
dialogInterface.dismiss();
|
||||
}
|
||||
});
|
||||
dialog = builder.create();
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.Set;
|
||||
|
||||
/**
|
||||
* External data source manager, which converts system-level events into My Tracks data events.
|
||||
*
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
class DataSourceManager {
|
||||
@@ -36,6 +36,7 @@ class DataSourceManager {
|
||||
void notifyPointsUpdated();
|
||||
void notifyPreferenceChanged(String key);
|
||||
void notifyLocationProviderEnabled(boolean enabled);
|
||||
void notifyLocationProviderAvailable(boolean available);
|
||||
void notifyLocationChanged(Location loc);
|
||||
void notifyHeadingChanged(float heading);
|
||||
}
|
||||
@@ -93,7 +94,7 @@ class DataSourceManager {
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
if (!LocationManager.GPS_PROVIDER.equals(provider)) return;
|
||||
|
||||
listener.notifyLocationProviderEnabled(status == LocationProvider.AVAILABLE);
|
||||
listener.notifyLocationProviderAvailable(status == LocationProvider.AVAILABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -168,7 +169,7 @@ class DataSourceManager {
|
||||
neededListeners.remove(ListenerDataType.SAMPLED_OUT_POINT_UPDATES);
|
||||
neededListeners.add(ListenerDataType.POINT_UPDATES);
|
||||
}
|
||||
|
||||
|
||||
Log.d(TAG, "Updating internal listeners to types " + neededListeners);
|
||||
|
||||
// Unnecessary = registered - needed
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -154,12 +154,12 @@ public class MyTracksProvider extends ContentProvider {
|
||||
// Sensor data.
|
||||
if (oldVersion <= 17) {
|
||||
Log.w(TAG, "Upgrade DB: Adding sensor column.");
|
||||
db.execSQL("ALTER TABLE " + TRACKPOINTS_TABLE
|
||||
db.execSQL("ALTER TABLE " + TRACKPOINTS_TABLE
|
||||
+ " ADD " + TrackPointsColumns.SENSOR + " BLOB");
|
||||
}
|
||||
if (oldVersion <= 18) {
|
||||
Log.w(TAG, "Upgrade DB: Adding tableid column.");
|
||||
db.execSQL("ALTER TABLE " + TRACKS_TABLE
|
||||
db.execSQL("ALTER TABLE " + TRACKS_TABLE
|
||||
+ " ADD " + TracksColumns.TABLEID + " STRING");
|
||||
}
|
||||
}
|
||||
@@ -186,7 +186,11 @@ public class MyTracksProvider extends ContentProvider {
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
DatabaseHelper dbHelper = new DatabaseHelper(getContext());
|
||||
db = dbHelper.getWritableDatabase();
|
||||
try {
|
||||
db = dbHelper.getWritableDatabase();
|
||||
} catch (SQLiteException e) {
|
||||
Log.e(TAG, "Unable to open database for writing", e);
|
||||
}
|
||||
return db != null;
|
||||
}
|
||||
|
||||
@@ -383,7 +387,7 @@ public class MyTracksProvider extends ContentProvider {
|
||||
|
||||
if (ApiFeatures.getInstance().canReuseSQLiteQueryBuilder()) {
|
||||
Log.i(Constants.TAG,
|
||||
"Build query: " + qb.buildQuery(projection, selection, selectionArgs,
|
||||
"Build query: " + qb.buildQuery(projection, selection, selectionArgs,
|
||||
null, null, sortOrder, null));
|
||||
}
|
||||
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -17,11 +17,12 @@ package com.google.android.apps.mytracks.content;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.DEFAULT_MIN_REQUIRED_ACCURACY;
|
||||
import static com.google.android.apps.mytracks.Constants.MAX_DISPLAYED_WAYPOINTS_POINTS;
|
||||
import static com.google.android.apps.mytracks.Constants.TARGET_DISPLAYED_TRACK_POINTS;
|
||||
import static com.google.android.apps.mytracks.Constants.MAX_LOCATION_AGE_MS;
|
||||
import static com.google.android.apps.mytracks.Constants.MAX_NETWORK_AGE_MS;
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
import static com.google.android.apps.mytracks.Constants.TARGET_DISPLAYED_TRACK_POINTS;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.content.DataSourceManager.DataSourceListener;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.DoubleBufferedLocationFactory;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
||||
@@ -40,7 +41,6 @@ import android.location.LocationManager;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
@@ -129,6 +129,12 @@ public class TrackDataHub {
|
||||
TrackDataHub.this.notifyFixType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyLocationProviderAvailable(boolean available) {
|
||||
hasFix = available;
|
||||
TrackDataHub.this.notifyFixType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyLocationChanged(Location loc) {
|
||||
TrackDataHub.this.notifyLocationChanged(loc,
|
||||
@@ -150,24 +156,21 @@ public class TrackDataHub {
|
||||
|
||||
// Get content notifications on the main thread, send listener callbacks in another.
|
||||
// This ensures listener calls are serialized.
|
||||
private final HandlerThread listenerHandlerThread;
|
||||
private final Handler listenerHandler;
|
||||
private HandlerThread listenerHandlerThread;
|
||||
private Handler listenerHandler;
|
||||
|
||||
/** Manager for external listeners (those from activities). */
|
||||
private final TrackDataListeners listeners;
|
||||
private final TrackDataListeners dataListeners;
|
||||
|
||||
/** Wrapper for interacting with system data managers. */
|
||||
private final DataSourcesWrapper dataSources;
|
||||
private DataSourcesWrapper dataSources;
|
||||
|
||||
/** Manager for system data listener registrations. */
|
||||
private final DataSourceManager dataSourceManager;
|
||||
private DataSourceManager dataSourceManager;
|
||||
|
||||
/** Condensed listener for system data listener events. */
|
||||
private final DataSourceListener dataSourceListener = new HubDataSourceListener();
|
||||
|
||||
/** Whether we've been started. */
|
||||
private boolean started;
|
||||
|
||||
// Cached preference values
|
||||
private int minRequiredAccuracy;
|
||||
private boolean useMetricUnits;
|
||||
@@ -192,28 +195,34 @@ public class TrackDataHub {
|
||||
private int lastSamplingFrequency;
|
||||
private DoubleBufferedLocationFactory locationFactory;
|
||||
|
||||
private static TrackDataHub startedInstance;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
* Builds a new {@link TrackDataHub} instance.
|
||||
*/
|
||||
public TrackDataHub(Context ctx, SharedPreferences preferences,
|
||||
MyTracksProviderUtils providerUtils) {
|
||||
this(ctx, new DataSourcesWrapperImpl(ctx, preferences), new TrackDataListeners(),
|
||||
preferences, providerUtils, TARGET_DISPLAYED_TRACK_POINTS);
|
||||
public synchronized static TrackDataHub newInstance(Context context) {
|
||||
// Ensure our singleton is never bound to an activity, to avoid memory leaks.
|
||||
context = context.getApplicationContext();
|
||||
|
||||
SharedPreferences preferences = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||
MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
return new TrackDataHub(context,
|
||||
new TrackDataListeners(),
|
||||
preferences, providerUtils,
|
||||
TARGET_DISPLAYED_TRACK_POINTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection constructor.
|
||||
*/
|
||||
// @VisibleForTesting
|
||||
TrackDataHub(Context ctx, DataSourcesWrapper dataSources, TrackDataListeners listeners,
|
||||
SharedPreferences preferences, MyTracksProviderUtils providerUtils, int targetNumPoints) {
|
||||
TrackDataHub(Context ctx, TrackDataListeners listeners, SharedPreferences preferences,
|
||||
MyTracksProviderUtils providerUtils, int targetNumPoints) {
|
||||
this.context = ctx;
|
||||
this.listeners = listeners;
|
||||
this.dataListeners = listeners;
|
||||
this.preferences = preferences;
|
||||
this.providerUtils = providerUtils;
|
||||
this.dataSources = dataSources;
|
||||
this.targetNumPoints = targetNumPoints;
|
||||
this.dataSourceManager = new DataSourceManager(dataSourceListener, dataSources);
|
||||
this.locationFactory = new DoubleBufferedLocationFactory();
|
||||
|
||||
SELECTED_TRACK_KEY = context.getString(R.string.selected_track_key);
|
||||
@@ -222,10 +231,6 @@ public class TrackDataHub {
|
||||
METRIC_UNITS_KEY = context.getString(R.string.metric_units_key);
|
||||
SPEED_REPORTING_KEY = context.getString(R.string.report_speed_key);
|
||||
|
||||
listenerHandlerThread = new HandlerThread("trackDataContentThread");
|
||||
listenerHandlerThread.start();
|
||||
listenerHandler = new Handler(listenerHandlerThread.getLooper());
|
||||
|
||||
resetState();
|
||||
}
|
||||
|
||||
@@ -235,11 +240,17 @@ public class TrackDataHub {
|
||||
*/
|
||||
public void start() {
|
||||
Log.i(TAG, "TrackDataHub.start");
|
||||
if (started) {
|
||||
if (startedInstance != null) {
|
||||
Log.w(TAG, "Already started, ignoring");
|
||||
return;
|
||||
}
|
||||
started = true;
|
||||
startedInstance = this;
|
||||
|
||||
listenerHandlerThread = new HandlerThread("trackDataContentThread");
|
||||
listenerHandlerThread.start();
|
||||
listenerHandler = new Handler(listenerHandlerThread.getLooper());
|
||||
dataSources = newDataSources();
|
||||
dataSourceManager = new DataSourceManager(dataSourceListener, dataSources);
|
||||
|
||||
// This may or may not register internal listeners, depending on whether
|
||||
// we already had external listeners.
|
||||
@@ -250,12 +261,23 @@ public class TrackDataHub {
|
||||
loadDataForAllListeners();
|
||||
}
|
||||
|
||||
private void loadSharedPreferences() {
|
||||
selectedTrackId = preferences.getLong(SELECTED_TRACK_KEY, -1);
|
||||
useMetricUnits = preferences.getBoolean(METRIC_UNITS_KEY, true);
|
||||
reportSpeed = preferences.getBoolean(SPEED_REPORTING_KEY, true);
|
||||
minRequiredAccuracy = preferences.getInt(MIN_REQUIRED_ACCURACY_KEY,
|
||||
DEFAULT_MIN_REQUIRED_ACCURACY);
|
||||
// @VisibleForTesting
|
||||
protected DataSourcesWrapper newDataSources() {
|
||||
return new DataSourcesWrapperImpl(context, preferences);
|
||||
}
|
||||
|
||||
/**
|
||||
* If there's an instance for which {@link start} has been called, returns it.
|
||||
*
|
||||
* @return the started instance
|
||||
* @throws IllegalStateException if there isn't a started instance
|
||||
*/
|
||||
public static TrackDataHub getStartedInstance() {
|
||||
if (startedInstance == null) {
|
||||
throw new IllegalStateException("Data hub not started");
|
||||
}
|
||||
|
||||
return startedInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,25 +286,42 @@ public class TrackDataHub {
|
||||
*/
|
||||
public void stop() {
|
||||
Log.i(TAG, "TrackDataHub.stop");
|
||||
if (!started) {
|
||||
if (!isStarted()) {
|
||||
Log.w(TAG, "Not started, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
// Unregister internal listeners even if there are external listeners registered.
|
||||
dataSourceManager.unregisterAllListeners();
|
||||
listenerHandlerThread.getLooper().quit();
|
||||
|
||||
started = false;
|
||||
startedInstance = null;
|
||||
|
||||
dataSources = null;
|
||||
dataSourceManager = null;
|
||||
listenerHandlerThread = null;
|
||||
listenerHandler = null;
|
||||
}
|
||||
|
||||
/** Permanently invalidates and throws away all resources used by this class. */
|
||||
public void destroy() {
|
||||
if (started) {
|
||||
throw new IllegalStateException("Can only destroy the data hub after it's been stopped");
|
||||
private boolean isStarted() {
|
||||
return startedInstance != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
if (isStarted() || listenerHandlerThread.isAlive()) {
|
||||
Log.e(TAG, "Forgot to stop() TrackDataHub");
|
||||
}
|
||||
|
||||
ApiFeatures.getInstance().getApiPlatformAdapter()
|
||||
.stopHandlerThread(listenerHandlerThread);
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
private void loadSharedPreferences() {
|
||||
selectedTrackId = preferences.getLong(SELECTED_TRACK_KEY, -1);
|
||||
useMetricUnits = preferences.getBoolean(METRIC_UNITS_KEY, true);
|
||||
reportSpeed = preferences.getBoolean(SPEED_REPORTING_KEY, true);
|
||||
minRequiredAccuracy = preferences.getInt(MIN_REQUIRED_ACCURACY_KEY,
|
||||
DEFAULT_MIN_REQUIRED_ACCURACY);
|
||||
}
|
||||
|
||||
/** Updates known magnetic declination if needed. */
|
||||
@@ -325,6 +364,10 @@ public class TrackDataHub {
|
||||
* is not available or doesn't have a fix.
|
||||
*/
|
||||
public void forceUpdateLocation() {
|
||||
if (!isStarted()) {
|
||||
Log.w(TAG, "Not started, not forcing location update");
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "Forcing location update");
|
||||
|
||||
Location loc = dataSources.getLastKnownLocation();
|
||||
@@ -336,7 +379,7 @@ public class TrackDataHub {
|
||||
|
||||
/** Returns the ID of the currently-selected track. */
|
||||
public long getSelectedTrackId() {
|
||||
if (!started) {
|
||||
if (!isStarted()) {
|
||||
loadSharedPreferences();
|
||||
}
|
||||
return selectedTrackId;
|
||||
@@ -347,17 +390,9 @@ public class TrackDataHub {
|
||||
return getSelectedTrackId() > 0;
|
||||
}
|
||||
|
||||
/** Returns whether we're currently recording a track. */
|
||||
public boolean isRecording() {
|
||||
if (!started) {
|
||||
loadSharedPreferences();
|
||||
}
|
||||
return preferences.getLong(RECORDING_TRACK_KEY, -1) > 0;
|
||||
}
|
||||
|
||||
/** Returns whether the selected track is still being recorded. */
|
||||
public boolean isRecordingSelected() {
|
||||
if (!started) {
|
||||
if (!isStarted()) {
|
||||
loadSharedPreferences();
|
||||
}
|
||||
long recordingTrackId = preferences.getLong(RECORDING_TRACK_KEY, -1);
|
||||
@@ -377,10 +412,10 @@ public class TrackDataHub {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save the selection to memory and flash.
|
||||
// Save the selection to memory and flush.
|
||||
selectedTrackId = trackId;
|
||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
|
||||
preferences.edit().putLong(SELECTED_TRACK_KEY, trackId));
|
||||
selectedTrackId = trackId;
|
||||
|
||||
// Force it to reload data from the beginning.
|
||||
Log.d(TAG, "Loading track");
|
||||
@@ -408,26 +443,27 @@ public class TrackDataHub {
|
||||
|
||||
public void registerTrackDataListener(
|
||||
TrackDataListener listener, EnumSet<ListenerDataType> dataTypes) {
|
||||
synchronized (listeners) {
|
||||
ListenerRegistration registration = listeners.registerTrackDataListener(listener, dataTypes);
|
||||
synchronized (dataListeners) {
|
||||
ListenerRegistration registration =
|
||||
dataListeners.registerTrackDataListener(listener, dataTypes);
|
||||
|
||||
// Don't load any data or start internal listeners if start() hasn't been
|
||||
// called. When it is called, we'll do both things.
|
||||
if (!started) return;
|
||||
if (!isStarted()) return;
|
||||
|
||||
reloadDataForListener(registration);
|
||||
loadNewDataForListener(registration);
|
||||
|
||||
dataSourceManager.updateAllListeners(getNeededListenerTypes());
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterTrackDataListener(TrackDataListener listener) {
|
||||
synchronized (listeners) {
|
||||
listeners.unregisterTrackDataListener(listener);
|
||||
synchronized (dataListeners) {
|
||||
dataListeners.unregisterTrackDataListener(listener);
|
||||
|
||||
// Don't load any data or start internal listeners if start() hasn't been
|
||||
// called. When it is called, we'll do both things.
|
||||
if (!started) return;
|
||||
if (!isStarted()) return;
|
||||
|
||||
dataSourceManager.updateAllListeners(getNeededListenerTypes());
|
||||
}
|
||||
@@ -438,30 +474,32 @@ public class TrackDataHub {
|
||||
*/
|
||||
public void reloadDataForListener(TrackDataListener listener) {
|
||||
ListenerRegistration registration;
|
||||
synchronized (listeners) {
|
||||
registration = listeners.getRegistration(listener);
|
||||
reloadDataForListener(registration);
|
||||
synchronized (dataListeners) {
|
||||
registration = dataListeners.getRegistration(listener);
|
||||
registration.resetState();
|
||||
loadNewDataForListener(registration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads all track data received so far into the specified listeners.
|
||||
*
|
||||
* Assumes it's called from a block that synchronizes on {@link #listeners}.
|
||||
*
|
||||
* Assumes it's called from a block that synchronizes on {@link #dataListeners}.
|
||||
*/
|
||||
private void reloadDataForListener(final ListenerRegistration registration) {
|
||||
if (!started) {
|
||||
private void loadNewDataForListener(final ListenerRegistration registration) {
|
||||
if (!isStarted()) {
|
||||
Log.w(TAG, "Not started, not reloading");
|
||||
return;
|
||||
}
|
||||
if (registration == null) {
|
||||
Log.w(TAG, "Not reloading for null registration");
|
||||
return;
|
||||
}
|
||||
|
||||
// If a listener happens to be added after this method but before the Runnable below is
|
||||
// executed, it will have triggered a separate call to load data only up to the point this
|
||||
// listener got to. This is ensured by being synchronized on listeners.
|
||||
final boolean isOnlyListener = (listeners.getNumListeners() == 1);
|
||||
final boolean isOnlyListener = (dataListeners.getNumListeners() == 1);
|
||||
|
||||
runInListenerThread(new Runnable() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -542,12 +580,12 @@ public class TrackDataHub {
|
||||
* Reloads all track data received so far into the specified listeners.
|
||||
*/
|
||||
private void loadDataForAllListeners() {
|
||||
if (!started) {
|
||||
if (!isStarted()) {
|
||||
Log.w(TAG, "Not started, not reloading");
|
||||
return;
|
||||
}
|
||||
synchronized (listeners) {
|
||||
if (!listeners.hasListeners()) {
|
||||
synchronized (dataListeners) {
|
||||
if (!dataListeners.hasListeners()) {
|
||||
Log.d(TAG, "No listeners, not reloading");
|
||||
return;
|
||||
}
|
||||
@@ -604,24 +642,27 @@ public class TrackDataHub {
|
||||
} else if (SPEED_REPORTING_KEY.equals(key)) {
|
||||
reportSpeed = preferences.getBoolean(SPEED_REPORTING_KEY, true);
|
||||
notifySpeedReportingChanged();
|
||||
} else if (SELECTED_TRACK_KEY.equals(key)) {
|
||||
long trackId = preferences.getLong(SELECTED_TRACK_KEY, -1);
|
||||
loadTrack(trackId);
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when the speed/pace reporting preference changes. */
|
||||
private void notifySpeedReportingChanged() {
|
||||
if (!started) return;
|
||||
if (!isStarted()) return;
|
||||
|
||||
runInListenerThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Set<TrackDataListener> displayListeners =
|
||||
getListenersFor(ListenerDataType.DISPLAY_PREFERENCES);
|
||||
getListenersFor(ListenerDataType.DISPLAY_PREFERENCES);
|
||||
|
||||
for (TrackDataListener listener : displayListeners) {
|
||||
// TODO: Do the reloading just once for all interested listeners
|
||||
if (listener.onReportSpeedChanged(reportSpeed)) {
|
||||
synchronized (listeners) {
|
||||
reloadDataForListener(listeners.getRegistration(listener));
|
||||
synchronized (dataListeners) {
|
||||
reloadDataForListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -631,17 +672,17 @@ public class TrackDataHub {
|
||||
|
||||
/** Called when the metric units setting changes. */
|
||||
private void notifyUnitsChanged() {
|
||||
if (!started) return;
|
||||
if (!isStarted()) return;
|
||||
|
||||
runInListenerThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Set<TrackDataListener> displayListeners = getListenersFor(ListenerDataType.DISPLAY_PREFERENCES);
|
||||
Set<TrackDataListener> displayListeners = getListenersFor(ListenerDataType.DISPLAY_PREFERENCES);
|
||||
|
||||
for (TrackDataListener listener : displayListeners) {
|
||||
if (listener.onUnitsChanged(useMetricUnits)) {
|
||||
synchronized (listeners) {
|
||||
reloadDataForListener(listeners.getRegistration(listener));
|
||||
synchronized (dataListeners) {
|
||||
reloadDataForListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -654,9 +695,6 @@ public class TrackDataHub {
|
||||
final TrackDataListener.ProviderState state;
|
||||
if (!hasProviderEnabled) {
|
||||
state = ProviderState.DISABLED;
|
||||
|
||||
// Give a global warning about this state.
|
||||
Toast.makeText(context, R.string.error_no_gps_location_provider, Toast.LENGTH_LONG).show();
|
||||
} else if (!hasFix) {
|
||||
state = ProviderState.NO_FIX;
|
||||
} else if (!hasGoodFix) {
|
||||
@@ -711,7 +749,7 @@ public class TrackDataHub {
|
||||
if (isGpsLocation) {
|
||||
// We consider a good fix to be a recent one with reasonable accuracy.
|
||||
hasFix = !isLocationOld(location, now, MAX_LOCATION_AGE_MS);
|
||||
hasGoodFix = (location != null && location.getAccuracy() <= minRequiredAccuracy);
|
||||
hasGoodFix = (location.getAccuracy() <= minRequiredAccuracy);
|
||||
} else {
|
||||
if (!isLocationOld(lastSeenLocation, now, MAX_LOCATION_AGE_MS)) {
|
||||
// This is a network location, but we have a recent/valid GPS location, just ignore this.
|
||||
@@ -794,10 +832,6 @@ public class TrackDataHub {
|
||||
public void run() {
|
||||
for (TrackDataListener listener : listeners) {
|
||||
listener.onSelectedTrackChanged(track, isRecordingSelected());
|
||||
|
||||
if (track != null) {
|
||||
listener.onTrackUpdated(track);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -851,7 +885,7 @@ public class TrackDataHub {
|
||||
if (!LocationUtils.isValidLocation(waypoint.getLocation())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
for (TrackDataListener listener : listeners) {
|
||||
listener.onNewWaypoint(waypoint);
|
||||
}
|
||||
@@ -862,7 +896,7 @@ public class TrackDataHub {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (TrackDataListener listener : listeners) {
|
||||
listener.onNewWaypointsDone();
|
||||
}
|
||||
@@ -937,7 +971,7 @@ public class TrackDataHub {
|
||||
|
||||
Log.i(TAG, "Resampling point set after " + numLoadedPoints + " points.");
|
||||
resetState();
|
||||
synchronized (listeners) {
|
||||
synchronized (dataListeners) {
|
||||
sampledListeners = getListenersFor(ListenerDataType.POINT_UPDATES);
|
||||
sampledOutListeners = getListenersFor(ListenerDataType.SAMPLED_OUT_POINT_UPDATES);
|
||||
}
|
||||
@@ -997,6 +1031,7 @@ public class TrackDataHub {
|
||||
// no matter how many points we get in the newest batch, we'll never exceed
|
||||
// MAX_DISPLAYED_TRACK_POINTS = 2 * TARGET_DISPLAYED_TRACK_POINTS before resampling.
|
||||
long numTotalPoints = lastStoredLocationId - localFirstSeenLocationId;
|
||||
numTotalPoints = Math.max(0L, numTotalPoints);
|
||||
pointSamplingFrequency = (int) (1 + numTotalPoints / targetNumPoints);
|
||||
}
|
||||
|
||||
@@ -1021,7 +1056,7 @@ public class TrackDataHub {
|
||||
listener.onNewTrackPointsDone();
|
||||
|
||||
// Update the listener state
|
||||
ListenerRegistration registration = listeners.getRegistration(listener);
|
||||
ListenerRegistration registration = dataListeners.getRegistration(listener);
|
||||
if (registration != null) {
|
||||
registration.lastTrackId = currentSelectedTrackId;
|
||||
registration.lastPointId = localLastSeenLocationId;
|
||||
@@ -1034,7 +1069,7 @@ public class TrackDataHub {
|
||||
private void notifyNewPoint(Location location,
|
||||
long locationId,
|
||||
long lastStoredLocationId,
|
||||
int numLoadedPoints,
|
||||
int loadedPoints,
|
||||
int pointSamplingFrequency,
|
||||
Set<TrackDataListener> sampledListeners,
|
||||
Set<TrackDataListener> sampledOutListeners) {
|
||||
@@ -1053,7 +1088,7 @@ public class TrackDataHub {
|
||||
// - Is the last point and we are not recording this track.
|
||||
boolean recordingSelected = isRecordingSelected();
|
||||
boolean includeInSample =
|
||||
(numLoadedPoints % pointSamplingFrequency == 0 ||
|
||||
(loadedPoints % pointSamplingFrequency == 0 ||
|
||||
(!recordingSelected && locationId == lastStoredLocationId));
|
||||
|
||||
if (!includeInSample) {
|
||||
@@ -1071,17 +1106,23 @@ public class TrackDataHub {
|
||||
|
||||
// @VisibleForTesting
|
||||
protected void runInListenerThread(Runnable runnable) {
|
||||
if (listenerHandler == null) {
|
||||
// Use a Throwable to ensure the stack trace is logged.
|
||||
Log.e(TAG, "Tried to use listener thread before start()", new Throwable());
|
||||
return;
|
||||
}
|
||||
|
||||
listenerHandler.post(runnable);
|
||||
}
|
||||
|
||||
private Set<TrackDataListener> getListenersFor(ListenerDataType type) {
|
||||
synchronized (listeners) {
|
||||
return listeners.getListenersFor(type);
|
||||
synchronized (dataListeners) {
|
||||
return dataListeners.getListenersFor(type);
|
||||
}
|
||||
}
|
||||
|
||||
private EnumSet<ListenerDataType> getNeededListenerTypes() {
|
||||
EnumSet<ListenerDataType> neededTypes = listeners.getAllRegisteredTypes();
|
||||
EnumSet<ListenerDataType> neededTypes = dataListeners.getAllRegisteredTypes();
|
||||
|
||||
// We always want preference updates.
|
||||
neededTypes.add(ListenerDataType.DISPLAY_PREFERENCES);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -57,6 +57,13 @@ class TrackDataListeners {
|
||||
return types.contains(type);
|
||||
}
|
||||
|
||||
public void resetState() {
|
||||
lastTrackId = 0L;
|
||||
lastPointId = 0L;
|
||||
lastSamplingFrequency = 0;
|
||||
numLoadedPoints = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ListenerRegistration [listener=" + listener + ", types=" + types
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -20,21 +20,32 @@ import android.content.Intent;
|
||||
/**
|
||||
* This interface describes a class that will fetch and maintain a Google
|
||||
* authentication token.
|
||||
*
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public interface AuthManager {
|
||||
/**
|
||||
* Callback for authentication token retrieval operations.
|
||||
*/
|
||||
public interface AuthCallback {
|
||||
/**
|
||||
* Indicates that we're done fetching an auth token.
|
||||
*
|
||||
* @param success if true, indicates we have the requested auth token available
|
||||
* to be retrieved using {@link AuthManager#getAuthToken}
|
||||
*/
|
||||
void onAuthResult(boolean success);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the login process. The user should be asked to login if they
|
||||
* haven't already. The {@link Runnable} provided will be executed when the
|
||||
* auth token is successfully fetched.
|
||||
* haven't already. The {@link AuthCallback} provided will be executed when the
|
||||
* auth token fetching is done (successfully or not).
|
||||
*
|
||||
* @param whenFinished A {@link Runnable} to execute when the auth token
|
||||
* has been successfully fetched and is available via
|
||||
* {@link #getAuthToken()}
|
||||
* @param whenFinished A {@link AuthCallback} to execute when the auth token
|
||||
* fetching is done
|
||||
*/
|
||||
public abstract void doLogin(Runnable whenFinished, Object o);
|
||||
void doLogin(AuthCallback whenFinished, Object o);
|
||||
|
||||
/**
|
||||
* The {@link android.app.Activity} owner of this class should call this
|
||||
@@ -49,11 +60,8 @@ public interface AuthManager {
|
||||
* {@link android.app.Activity#onActivityResult} function
|
||||
* @param results The data passed in to the {@link android.app.Activity}'s
|
||||
* {@link android.app.Activity#onActivityResult} function
|
||||
* @return True if the auth token was fetched or we aren't done fetching
|
||||
* the auth token, or False if there was an error or the request was
|
||||
* canceled
|
||||
*/
|
||||
public abstract boolean authResult(int resultCode, Intent results);
|
||||
void authResult(int resultCode, Intent results);
|
||||
|
||||
/**
|
||||
* Returns the current auth token. Response may be null if no valid auth
|
||||
@@ -62,7 +70,7 @@ public interface AuthManager {
|
||||
* @return The current auth token or null if no auth token has been
|
||||
* fetched
|
||||
*/
|
||||
public abstract String getAuthToken();
|
||||
String getAuthToken();
|
||||
|
||||
/**
|
||||
* Invalidates the existing auth token and request a new one. The
|
||||
@@ -72,6 +80,14 @@ public interface AuthManager {
|
||||
* @param whenFinished A {@link Runnable} to execute when a new auth token
|
||||
* is successfully fetched
|
||||
*/
|
||||
public abstract void invalidateAndRefresh(Runnable whenFinished);
|
||||
void invalidateAndRefresh(AuthCallback whenFinished);
|
||||
|
||||
/**
|
||||
* Returns an object that represents the given account, if possible.
|
||||
*
|
||||
* @param accountName the name of the account
|
||||
* @param accountType the type of the account
|
||||
* @return the account object
|
||||
*/
|
||||
Object getAccountObject(String accountName, String accountType);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
@@ -24,7 +24,7 @@ import android.util.Log;
|
||||
|
||||
/**
|
||||
* A factory for getting the platform specific AuthManager.
|
||||
*
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class AuthManagerFactory {
|
||||
@@ -46,12 +46,10 @@ public class AuthManagerFactory {
|
||||
public static AuthManager getAuthManager(Activity activity, int code,
|
||||
Bundle extras, boolean requireGoogle, String service) {
|
||||
if (useModernAuthManager()) {
|
||||
Log.i(Constants.TAG,
|
||||
"Creating modern auth manager: " + service);
|
||||
return new ModernAuthManager(activity, code, extras, requireGoogle, service);
|
||||
Log.i(TAG, "Creating modern auth manager: " + service);
|
||||
return new ModernAuthManager(activity, service);
|
||||
} else {
|
||||
Log.i(Constants.TAG,
|
||||
"Creating legacy auth manager: " + service);
|
||||
Log.i(TAG, "Creating legacy auth manager: " + service);
|
||||
return new AuthManagerOld(activity, code, extras, requireGoogle, service);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,6 @@ import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* AuthManager keeps track of the current auth token for a user. The advantage
|
||||
* over just passing around a String is that this class can renew the auth
|
||||
@@ -47,18 +44,12 @@ public class AuthManagerOld implements AuthManager {
|
||||
/** The name of the service to authorize for. */
|
||||
private final String service;
|
||||
|
||||
/** A list of handlers to call when a new auth token is fetched. */
|
||||
private final Vector<Runnable> newTokenListeners = new Vector<Runnable>();
|
||||
/** The handler to call when a new auth token is fetched. */
|
||||
private AuthCallback authCallback;
|
||||
|
||||
/** The most recently fetched auth token or null if none is available. */
|
||||
private String authToken;
|
||||
|
||||
/**
|
||||
* The number of handlers at the beginning of the above list that shouldn't
|
||||
* be removed after they are called.
|
||||
*/
|
||||
private int stickyNewTokenListenerCount;
|
||||
|
||||
/**
|
||||
* AuthManager requires many of the same parameters as
|
||||
* {@link GoogleLoginServiceHelper#getCredentials(Activity, int, Bundle,
|
||||
@@ -88,15 +79,9 @@ public class AuthManagerOld implements AuthManager {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.google.android.apps.mytracks.io.AuthManager#doLogin(java.lang.Runnable)
|
||||
*/
|
||||
public void doLogin(Runnable whenFinished, Object o) {
|
||||
synchronized (newTokenListeners) {
|
||||
if (whenFinished != null) {
|
||||
newTokenListeners.add(whenFinished);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void doLogin(AuthCallback callback, Object o) {
|
||||
authCallback = callback;
|
||||
activity.runOnUiThread(new LoginRunnable());
|
||||
}
|
||||
|
||||
@@ -111,50 +96,37 @@ public class AuthManagerOld implements AuthManager {
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.google.android.apps.mytracks.io.AuthManager#authResult(int, android.content.Intent)
|
||||
*/
|
||||
public boolean authResult(int resultCode, Intent results) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
authToken = results.getStringExtra(
|
||||
GoogleLoginServiceConstants.AUTHTOKEN_KEY);
|
||||
if (authToken == null) {
|
||||
GoogleLoginServiceHelper.getCredentials(
|
||||
activity, code, extras, requireGoogle, service, false);
|
||||
return true;
|
||||
} else {
|
||||
// Notify all active listeners that we have a new auth token.
|
||||
synchronized (newTokenListeners) {
|
||||
Iterator<Runnable> iter = newTokenListeners.iterator();
|
||||
while (iter.hasNext()) {
|
||||
iter.next().run();
|
||||
}
|
||||
iter = null;
|
||||
// Remove anything not in the sticky part of the list.
|
||||
newTokenListeners.setSize(stickyNewTokenListenerCount);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public void authResult(int resultCode, Intent results) {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
runAuthCallback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
authToken = results.getStringExtra(GoogleLoginServiceConstants.AUTHTOKEN_KEY);
|
||||
if (authToken == null) {
|
||||
// Retry, without prompting the user.
|
||||
GoogleLoginServiceHelper.getCredentials(
|
||||
activity, code, extras, requireGoogle, service, false);
|
||||
} else {
|
||||
// Notify all active listeners that we have a new auth token.
|
||||
runAuthCallback(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.google.android.apps.mytracks.io.AuthManager#getAuthToken()
|
||||
*/
|
||||
private void runAuthCallback(boolean success) {
|
||||
authCallback.onAuthResult(success);
|
||||
authCallback = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthToken() {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.google.android.apps.mytracks.io.AuthManager#invalidateAndRefresh(java.lang.Runnable)
|
||||
*/
|
||||
public void invalidateAndRefresh(Runnable whenFinished) {
|
||||
synchronized (newTokenListeners) {
|
||||
if (whenFinished != null) {
|
||||
newTokenListeners.add(whenFinished);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void invalidateAndRefresh(AuthCallback callback) {
|
||||
authCallback = callback;
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
GoogleLoginServiceHelper.invalidateAuthToken(activity, code, authToken);
|
||||
@@ -162,37 +134,8 @@ public class AuthManagerOld implements AuthManager {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link Runnable} to be executed every time the auth token is
|
||||
* updated. The {@link Runnable} will not be removed until manually removed
|
||||
* with {@link #removeStickyNewTokenListener(Runnable)}.
|
||||
*
|
||||
* @param listener The {@link Runnable} to execute every time a new auth
|
||||
* token is fetched
|
||||
*/
|
||||
public void addStickyNewTokenListener(Runnable listener) {
|
||||
synchronized (newTokenListeners) {
|
||||
newTokenListeners.add(0, listener);
|
||||
stickyNewTokenListenerCount++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops executing the given {@link Runnable} every time the auth token is
|
||||
* updated. This {@link Runnable} must have been added with
|
||||
* {@link #addStickyNewTokenListener(Runnable)} above. If the
|
||||
* {@link Runnable} was added more than once, only the first occurrence
|
||||
* will be removed.
|
||||
*
|
||||
* @param listener The {@link Runnable} to stop executing every time a new
|
||||
* auth token is fetched
|
||||
*/
|
||||
public void removeStickyNewTokenListener(Runnable listener) {
|
||||
synchronized (newTokenListeners) {
|
||||
if (stickyNewTokenListenerCount > 0
|
||||
&& newTokenListeners.remove(listener)) {
|
||||
stickyNewTokenListenerCount--;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Object getAccountObject(String accountName, String accountType) {
|
||||
throw new UnsupportedOperationException("Legacy auth manager knows nothing about accounts");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,16 +15,17 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io;
|
||||
|
||||
import com.google.android.accounts.Account;
|
||||
import com.google.android.accounts.AccountManager;
|
||||
import com.google.android.accounts.AccountManagerCallback;
|
||||
import com.google.android.accounts.AccountManagerFuture;
|
||||
import com.google.android.accounts.AuthenticatorException;
|
||||
import com.google.android.accounts.OperationCanceledException;
|
||||
import com.google.android.apps.mytracks.AccountChooser;
|
||||
import com.google.android.apps.mytracks.MyTracks;
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import static com.google.android.apps.mytracks.Constants.ACCOUNT_TYPE;
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.AccountChooser;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AccountManagerCallback;
|
||||
import android.accounts.AccountManagerFuture;
|
||||
import android.accounts.AuthenticatorException;
|
||||
import android.accounts.OperationCanceledException;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
@@ -50,7 +51,9 @@ public class ModernAuthManager implements AuthManager {
|
||||
|
||||
private final AccountManager accountManager;
|
||||
|
||||
private Runnable whenFinished;
|
||||
private AuthCallback authCallback;
|
||||
|
||||
private Account lastAccount;
|
||||
|
||||
/**
|
||||
* AuthManager requires many of the same parameters as
|
||||
@@ -64,16 +67,9 @@ public class ModernAuthManager implements AuthManager {
|
||||
* {@link Activity#onActivityResult} that calls
|
||||
* {@link #authResult(int, Intent)} when {@literal code} is the request
|
||||
* code
|
||||
* @param code The request code to pass to
|
||||
* {@link Activity#onActivityResult} when
|
||||
* {@link #authResult(int, Intent)} should be called
|
||||
* @param extras A {@link Bundle} of extras for
|
||||
* {@link com.google.android.googlelogindist.GoogleLoginServiceHelper}
|
||||
* @param requireGoogle True if the account must be a Google account
|
||||
* @param service The name of the service to authenticate as
|
||||
*/
|
||||
public ModernAuthManager(Activity activity, int code, Bundle extras,
|
||||
boolean requireGoogle, String service) {
|
||||
public ModernAuthManager(Activity activity, String service) {
|
||||
this.activity = activity;
|
||||
this.service = service;
|
||||
this.accountManager = AccountManager.get(activity);
|
||||
@@ -88,47 +84,45 @@ public class ModernAuthManager implements AuthManager {
|
||||
* has been successfully fetched and is available via
|
||||
* {@link #getAuthToken()}
|
||||
*/
|
||||
public void doLogin(final Runnable runnable, Object o) {
|
||||
this.whenFinished = runnable;
|
||||
public void doLogin(AuthCallback runnable, Object o) {
|
||||
this.authCallback = runnable;
|
||||
if (!(o instanceof Account)) {
|
||||
throw new IllegalArgumentException("FroyoAuthManager requires an account.");
|
||||
throw new IllegalArgumentException("ModernAuthManager requires an account.");
|
||||
}
|
||||
Account account = (Account) o;
|
||||
accountManager.getAuthToken(account, service, true,
|
||||
doLogin(account);
|
||||
}
|
||||
|
||||
private void doLogin(Account account) {
|
||||
// Keep the account in case we need to retry.
|
||||
this.lastAccount = account;
|
||||
|
||||
// NOTE: Many Samsung phones have a crashing bug in
|
||||
// AccountManager#getAuthToken(Account, String, boolean, AccountManagerCallback<Bundle>)
|
||||
// so we use the other version of the method.
|
||||
// More details here:
|
||||
// http://forum.xda-developers.com/showthread.php?p=15155487
|
||||
// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/accounts/AccountManagerService.java
|
||||
accountManager.getAuthToken(account, service, null, activity,
|
||||
new AccountManagerCallback<Bundle>() {
|
||||
public void run(AccountManagerFuture<Bundle> future) {
|
||||
try {
|
||||
Bundle result = future.getResult();
|
||||
|
||||
// AccountManager needs user to grant permission
|
||||
if (result.containsKey(AccountManager.KEY_INTENT)) {
|
||||
Intent intent = (Intent) result.get(AccountManager.KEY_INTENT);
|
||||
clearNewTaskFlag(intent);
|
||||
activity.startActivityForResult(intent, Constants.GET_LOGIN);
|
||||
return;
|
||||
}
|
||||
|
||||
authToken = result.getString(
|
||||
authToken = future.getResult().getString(
|
||||
AccountManager.KEY_AUTHTOKEN);
|
||||
Log.e(Constants.TAG, "Got auth token.");
|
||||
runWhenFinished();
|
||||
Log.i(TAG, "Got auth token");
|
||||
} catch (OperationCanceledException e) {
|
||||
Log.e(Constants.TAG, "Operation Canceled", e);
|
||||
Log.e(TAG, "Auth token operation Canceled", e);
|
||||
} catch (IOException e) {
|
||||
Log.e(Constants.TAG, "IOException", e);
|
||||
Log.e(TAG, "Auth token IO exception", e);
|
||||
} catch (AuthenticatorException e) {
|
||||
Log.e(Constants.TAG, "Authentication Failed", e);
|
||||
Log.e(TAG, "Authentication Failed", e);
|
||||
}
|
||||
|
||||
runAuthCallback();
|
||||
}
|
||||
}, null /* handler */);
|
||||
}
|
||||
|
||||
private static void clearNewTaskFlag(Intent intent) {
|
||||
int flags = intent.getFlags();
|
||||
flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
intent.setFlags(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link Activity} passed into the constructor should call this
|
||||
* function when it gets {@link Activity#onActivityResult} with the request
|
||||
@@ -145,16 +139,22 @@ public class ModernAuthManager implements AuthManager {
|
||||
* the auth token, or False if there was an error or the request was
|
||||
* canceled
|
||||
*/
|
||||
public boolean authResult(int resultCode, Intent results) {
|
||||
if (results != null) {
|
||||
authToken = results.getStringExtra(
|
||||
AccountManager.KEY_AUTHTOKEN);
|
||||
Log.w(Constants.TAG, "authResult: " + authToken);
|
||||
public void authResult(int resultCode, Intent results) {
|
||||
boolean retry = false;
|
||||
if (results == null) {
|
||||
Log.e(TAG, "No auth token!!");
|
||||
} else {
|
||||
Log.e(Constants.TAG, "No auth result results!!");
|
||||
authToken = results.getStringExtra(AccountManager.KEY_AUTHTOKEN);
|
||||
retry = results.getBooleanExtra("retry", false);
|
||||
}
|
||||
runWhenFinished();
|
||||
return authToken != null;
|
||||
|
||||
if (authToken == null && retry) {
|
||||
Log.i(TAG, "Retrying to get auth result");
|
||||
doLogin(lastAccount);
|
||||
return;
|
||||
}
|
||||
|
||||
runAuthCallback();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,21 +176,23 @@ public class ModernAuthManager implements AuthManager {
|
||||
* @param runnable A {@link Runnable} to execute when a new auth token
|
||||
* is successfully fetched
|
||||
*/
|
||||
public void invalidateAndRefresh(final Runnable runnable) {
|
||||
this.whenFinished = runnable;
|
||||
public void invalidateAndRefresh(final AuthCallback callback) {
|
||||
this.authCallback = callback;
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
accountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE,
|
||||
authToken);
|
||||
MyTracks.getInstance().getAccountChooser().chooseAccount(activity,
|
||||
accountManager.invalidateAuthToken(ACCOUNT_TYPE, authToken);
|
||||
authToken = null;
|
||||
|
||||
AccountChooser accountChooser = new AccountChooser();
|
||||
accountChooser.chooseAccount(activity,
|
||||
new AccountChooser.AccountHandler() {
|
||||
@Override
|
||||
public void handleAccountSelected(Account account) {
|
||||
public void onAccountSelected(Account account) {
|
||||
if (account != null) {
|
||||
doLogin(whenFinished, account);
|
||||
doLogin(account);
|
||||
} else {
|
||||
runWhenFinished();
|
||||
runAuthCallback();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -198,14 +200,22 @@ public class ModernAuthManager implements AuthManager {
|
||||
});
|
||||
}
|
||||
|
||||
private void runWhenFinished() {
|
||||
if (whenFinished != null) {
|
||||
private void runAuthCallback() {
|
||||
lastAccount = null;
|
||||
|
||||
if (authCallback != null) {
|
||||
(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
whenFinished.run();
|
||||
authCallback.onAuthResult(authToken != null);
|
||||
authCallback = null;
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAccountObject(String accountName, String accountType) {
|
||||
return new Account(accountName, accountType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracks;
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.ProgressIndicator;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.io.docs.DocsHelper;
|
||||
@@ -25,15 +25,13 @@ import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
|
||||
import com.google.android.common.gdata.AndroidXmlParserFactory;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.wireless.gdata.client.GDataClient;
|
||||
import com.google.wireless.gdata.client.GDataServiceClient;
|
||||
import com.google.wireless.gdata.docs.DocumentsClient;
|
||||
import com.google.wireless.gdata.docs.SpreadsheetsClient;
|
||||
import com.google.wireless.gdata.docs.XmlDocsGDataParserFactory;
|
||||
import com.google.wireless.gdata.client.GDataServiceClient;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -46,17 +44,15 @@ import java.io.IOException;
|
||||
public class SendToDocs {
|
||||
/** The GData service name for Google Spreadsheets (aka Trix) */
|
||||
public static final String GDATA_SERVICE_NAME_TRIX = "wise";
|
||||
|
||||
|
||||
/** The GData service name for the Google Docs Document List */
|
||||
public static final String GDATA_SERVICE_NAME_DOCLIST = "writely";
|
||||
|
||||
|
||||
private final Activity activity;
|
||||
private final AuthManager trixAuth;
|
||||
private final AuthManager docListAuth;
|
||||
private final long trackId;
|
||||
private final ProgressIndicator progressIndicator;
|
||||
private final boolean metricUnits;
|
||||
private final HandlerThread handlerThread;
|
||||
private final Handler handler;
|
||||
|
||||
private boolean createdNewSpreadSheet = false;
|
||||
|
||||
@@ -64,12 +60,13 @@ public class SendToDocs {
|
||||
private String statusMessage = "";
|
||||
private Runnable onCompletion = null;
|
||||
|
||||
|
||||
public SendToDocs(Activity activity, AuthManager trixAuth,
|
||||
AuthManager docListAuth, long trackId) {
|
||||
AuthManager docListAuth, ProgressIndicator progressIndicator) {
|
||||
this.activity = activity;
|
||||
this.trixAuth = trixAuth;
|
||||
this.docListAuth = docListAuth;
|
||||
this.trackId = trackId;
|
||||
this.progressIndicator = progressIndicator;
|
||||
|
||||
SharedPreferences preferences = activity.getSharedPreferences(
|
||||
Constants.SETTINGS_NAME, 0);
|
||||
@@ -80,24 +77,20 @@ public class SendToDocs {
|
||||
} else {
|
||||
metricUnits = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void sendToDocs(final long trackId) {
|
||||
Log.d(Constants.TAG,
|
||||
"Sending to Google Docs: trackId = " + trackId);
|
||||
handlerThread = new HandlerThread("SendToGoogleDocs");
|
||||
handlerThread.start();
|
||||
handler = new Handler(handlerThread.getLooper());
|
||||
}
|
||||
|
||||
public void run() {
|
||||
handler.post(new Runnable() {
|
||||
new Thread("SendToGoogleDocs") {
|
||||
@Override
|
||||
public void run() {
|
||||
doUpload();
|
||||
doUpload(trackId);
|
||||
}
|
||||
});
|
||||
}.start();
|
||||
}
|
||||
|
||||
private void doUpload() {
|
||||
private void doUpload(long trackId) {
|
||||
// TODO
|
||||
statusMessage = activity.getString(R.string.error_sending_to_fusiontables);
|
||||
success = false;
|
||||
@@ -162,7 +155,7 @@ public class SendToDocs {
|
||||
GDataWrapper<GDataServiceClient> docListWrapper = new GDataWrapper<GDataServiceClient>();
|
||||
docListWrapper.setAuthManager(docListAuth);
|
||||
docListWrapper.setRetryOnAuthFailure(true);
|
||||
|
||||
|
||||
GDataWrapper<GDataServiceClient> trixWrapper = new GDataWrapper<GDataServiceClient>();
|
||||
trixWrapper.setAuthManager(trixAuth);
|
||||
trixWrapper.setRetryOnAuthFailure(true);
|
||||
@@ -190,7 +183,7 @@ public class SendToDocs {
|
||||
// First try to find the spreadsheet:
|
||||
String spreadsheetId = null;
|
||||
try {
|
||||
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
|
||||
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
|
||||
sheetTitle);
|
||||
} catch (IOException e) {
|
||||
Log.i(Constants.TAG, "Spreadsheet lookup failed.", e);
|
||||
@@ -198,7 +191,7 @@ public class SendToDocs {
|
||||
}
|
||||
|
||||
if (spreadsheetId == null) {
|
||||
MyTracks.getInstance().setProgressValue(65);
|
||||
progressIndicator.setProgressValue(65);
|
||||
// Waiting a few seconds and trying again. Maybe the server just had a
|
||||
// hickup (unfortunately that happens quite a lot...).
|
||||
try {
|
||||
@@ -206,18 +199,18 @@ public class SendToDocs {
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(Constants.TAG, "Sleep interrupted", e);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
|
||||
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
|
||||
sheetTitle);
|
||||
} catch (IOException e) {
|
||||
Log.i(Constants.TAG, "2nd spreadsheet lookup failed.", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// We were unable to find an existing spreadsheet, so create a new one.
|
||||
MyTracks.getInstance().setProgressValue(70);
|
||||
progressIndicator.setProgressValue(70);
|
||||
if (spreadsheetId == null) {
|
||||
Log.i(Constants.TAG, "Creating new spreadsheet: " + sheetTitle);
|
||||
|
||||
@@ -229,11 +222,11 @@ public class SendToDocs {
|
||||
+ sheetTitle, e);
|
||||
return false;
|
||||
}
|
||||
MyTracks.getInstance().setProgressValue(80);
|
||||
progressIndicator.setProgressValue(80);
|
||||
createdNewSpreadSheet = true;
|
||||
|
||||
if (spreadsheetId == null) {
|
||||
MyTracks.getInstance().setProgressValue(85);
|
||||
progressIndicator.setProgressValue(85);
|
||||
// The previous creation might have succeeded even though GData
|
||||
// reported an error. Seems to be a know bug,
|
||||
// see http://code.google.com/p/gdata-issues/issues/detail?id=929
|
||||
@@ -247,7 +240,7 @@ public class SendToDocs {
|
||||
}
|
||||
|
||||
try {
|
||||
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
|
||||
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
|
||||
sheetTitle);
|
||||
} catch (IOException e) {
|
||||
Log.i(Constants.TAG, "Failed create-failed lookup", e);
|
||||
@@ -255,16 +248,16 @@ public class SendToDocs {
|
||||
}
|
||||
|
||||
if (spreadsheetId == null) {
|
||||
MyTracks.getInstance().setProgressValue(87);
|
||||
progressIndicator.setProgressValue(87);
|
||||
// Re-try
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(Constants.TAG, "Sleep interrupted", e);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
|
||||
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
|
||||
sheetTitle);
|
||||
} catch (IOException e) {
|
||||
Log.i(Constants.TAG, "Failed create-failed relookup", e);
|
||||
@@ -290,9 +283,9 @@ public class SendToDocs {
|
||||
return false;
|
||||
}
|
||||
|
||||
MyTracks.getInstance().setProgressValue(90);
|
||||
progressIndicator.setProgressValue(90);
|
||||
|
||||
docsHelper.addTrackRow(activity, trixAuth, spreadsheetId, worksheetId,
|
||||
docsHelper.addTrackRow(activity, trixAuth, spreadsheetId, worksheetId,
|
||||
track, metricUnits);
|
||||
Log.i(Constants.TAG, "Done uploading to docs.");
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.ProgressIndicator;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
@@ -156,6 +158,11 @@ public class SendToFusionTables implements Runnable {
|
||||
}
|
||||
|
||||
public static String getMapVisualizationUrl(Track track) {
|
||||
if (track == null || track.getStatistics() == null || track.getTableId() == null) {
|
||||
Log.w(TAG, "Unable to get track URL");
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO(leifhendrik): Determine correct bounding box and zoom level that will show the entire track.
|
||||
TripStatistics stats = track.getStatistics();
|
||||
double latE6 = stats.getBottom() + (stats.getTop() - stats.getBottom()) / 2;
|
||||
@@ -179,12 +186,17 @@ public class SendToFusionTables implements Runnable {
|
||||
|
||||
// Get the track meta-data
|
||||
Track track = providerUtils.getTrack(trackId);
|
||||
if (track == null) {
|
||||
Log.w(Constants.TAG, "Cannot get track.");
|
||||
return;
|
||||
}
|
||||
|
||||
String originalDescription = track.getDescription();
|
||||
|
||||
// Create a new table:
|
||||
progressIndicator.setProgressValue(PROGRESS_FUSION_TABLE_CREATE);
|
||||
progressIndicator.setProgressMessage(R.string.progress_message_creating_fusiontable);
|
||||
if (!createNewTable(track) || !makeTableUnlisted(tableId)) {
|
||||
if (!createNewTable(track) || !makeTableUnlisted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -207,7 +219,6 @@ public class SendToFusionTables implements Runnable {
|
||||
Log.d(Constants.TAG, "SendToFusionTables: Done: " + success);
|
||||
progressIndicator.setProgressValue(PROGRESS_COMPLETE);
|
||||
} finally {
|
||||
|
||||
final boolean finalSuccess = success;
|
||||
final int finalStatusMessageId = statusMessageId;
|
||||
context.runOnUiThread(new Runnable() {
|
||||
@@ -234,7 +245,7 @@ public class SendToFusionTables implements Runnable {
|
||||
return runUpdate(query);
|
||||
}
|
||||
|
||||
private boolean makeTableUnlisted(String tableId) {
|
||||
private boolean makeTableUnlisted() {
|
||||
Log.d(Constants.TAG, "Setting visibility to unlisted.");
|
||||
String query = "UPDATE TABLE " + tableId + " SET VISIBILITY = UNLISTED";
|
||||
return runUpdate(query);
|
||||
@@ -304,7 +315,7 @@ public class SendToFusionTables implements Runnable {
|
||||
|
||||
Cursor locationsCursor = providerUtils.getLocationsCursor(track.getId(), 0, -1, false);
|
||||
try {
|
||||
if (!locationsCursor.moveToFirst()) {
|
||||
if (locationsCursor == null || !locationsCursor.moveToFirst()) {
|
||||
Log.w(Constants.TAG, "Unable to get any points to upload");
|
||||
return false;
|
||||
}
|
||||
@@ -391,7 +402,9 @@ public class SendToFusionTables implements Runnable {
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
locationsCursor.close();
|
||||
if (locationsCursor != null) {
|
||||
locationsCursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,10 +433,10 @@ public class SendToFusionTables implements Runnable {
|
||||
* @return the kml.
|
||||
*/
|
||||
private String getKmlPoint(Location location) {
|
||||
StringBuilder builder = new StringBuilder("<Point><coordinates>");
|
||||
appendCoordinate(location, builder);
|
||||
builder.append("</coordinates></Point>");
|
||||
return builder.toString();
|
||||
StringBuilder builder = new StringBuilder("<Point><coordinates>");
|
||||
appendCoordinate(location, builder);
|
||||
builder.append("</coordinates></Point>");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -599,7 +612,7 @@ public class SendToFusionTables implements Runnable {
|
||||
// I am leaving the number of waypoints very high which should not be a
|
||||
// problem because we don't try to load them into objects all at the
|
||||
// same time.
|
||||
boolean success = true;
|
||||
boolean success = true;
|
||||
Cursor c = null;
|
||||
try {
|
||||
c = providerUtils.getWaypointsCursor(
|
||||
@@ -613,9 +626,9 @@ public class SendToFusionTables implements Runnable {
|
||||
Waypoint wpt = providerUtils.createWaypoint(c);
|
||||
Log.d(Constants.TAG, "SendToFusionTables: Creating waypoint.");
|
||||
success = createNewPoint(wpt.getName(), wpt.getDescription(), wpt.getLocation(),
|
||||
MARKER_TYPE_WAYPOINT);
|
||||
MARKER_TYPE_WAYPOINT);
|
||||
if (!success) {
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -637,7 +650,7 @@ public class SendToFusionTables implements Runnable {
|
||||
// to fit the completion percentage range alloted to track data upload.
|
||||
double totalPercentage =
|
||||
(totalLocationsRead + totalLocationsPrepared + totalLocationsUploaded)
|
||||
/ (totalLocations * 3);
|
||||
/ (totalLocations * 3.0);
|
||||
|
||||
double scaledPercentage = totalPercentage
|
||||
* (PROGRESS_UPLOAD_DATA_MAX - PROGRESS_UPLOAD_DATA_MIN) + PROGRESS_UPLOAD_DATA_MIN;
|
||||
@@ -681,8 +694,8 @@ public class SendToFusionTables implements Runnable {
|
||||
boolean success = response.isSuccessStatusCode;
|
||||
if (success) {
|
||||
byte[] result = new byte[1024];
|
||||
response.getContent().read(result);
|
||||
String s = Strings.fromBytesUtf8(result);
|
||||
int read = response.getContent().read(result);
|
||||
String s = new String(result, 0, read, "UTF8");
|
||||
String[] lines = s.split(Strings.LINE_SEPARATOR);
|
||||
if (lines[0].equals("tableid")) {
|
||||
tableId = lines[1];
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -76,7 +76,7 @@ public class SendToMyMaps implements Runnable {
|
||||
public interface OnSendCompletedListener {
|
||||
void onSendCompleted(String mapId, boolean success, int statusMessage);
|
||||
}
|
||||
|
||||
|
||||
public SendToMyMaps(Activity context, String mapId, AuthManager auth,
|
||||
long trackId, ProgressIndicator progressIndicator,
|
||||
OnSendCompletedListener onCompletion) {
|
||||
@@ -100,18 +100,22 @@ public class SendToMyMaps implements Runnable {
|
||||
int statusMessageId = R.string.error_sending_to_mymap;
|
||||
boolean success = true;
|
||||
try {
|
||||
progressIndicator.setProgressValue(1);
|
||||
progressIndicator.setProgressMessage(
|
||||
R.string.progress_message_reading_track);
|
||||
|
||||
|
||||
// Get the track meta-data
|
||||
Track track = providerUtils.getTrack(trackId);
|
||||
if (track == null) {
|
||||
Log.w(Constants.TAG, "Cannot get track.");
|
||||
return;
|
||||
}
|
||||
|
||||
String originalDescription = track.getDescription();
|
||||
track.setDescription("<p>" + track.getDescription() + "</p><p>"
|
||||
+ stringUtils.generateTrackDescription(track, null, null) + "</p>");
|
||||
|
||||
mapsClient = new MapsFacade(context, auth);
|
||||
|
||||
|
||||
// Create a new map if necessary:
|
||||
boolean isNewMap = mapId.equals(NEW_MAP_ID);
|
||||
if (isNewMap) {
|
||||
@@ -166,7 +170,7 @@ public class SendToMyMaps implements Runnable {
|
||||
Log.w(TAG, "SendToMyMaps: upload waypoints failed.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (success) {
|
||||
statusMessageId = isNewMap
|
||||
? R.string.status_new_mymap_has_been_created
|
||||
@@ -178,7 +182,7 @@ public class SendToMyMaps implements Runnable {
|
||||
if (mapsClient != null) {
|
||||
mapsClient.cleanUp();
|
||||
}
|
||||
|
||||
|
||||
final boolean finalSuccess = success;
|
||||
final int finalStatusMessageId = statusMessageId;
|
||||
context.runOnUiThread(new Runnable() {
|
||||
@@ -206,17 +210,17 @@ public class SendToMyMaps implements Runnable {
|
||||
Cursor locationsCursor =
|
||||
providerUtils.getLocationsCursor(track.getId(), 0, -1, false);
|
||||
try {
|
||||
if (!locationsCursor.moveToFirst()) {
|
||||
if (locationsCursor == null || !locationsCursor.moveToFirst()) {
|
||||
Log.w(TAG, "Unable to get any points to upload");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
totalLocationsRead = 0;
|
||||
totalLocationsPrepared = 0;
|
||||
totalLocationsUploaded = 0;
|
||||
totalLocations = locationsCursor.getCount();
|
||||
totalSegmentsUploaded = 0;
|
||||
|
||||
|
||||
// Limit the number of elevation readings. Ideally we would want around 250.
|
||||
int elevationSamplingFrequency =
|
||||
Math.max(1, (int) (totalLocations / 250.0));
|
||||
@@ -224,12 +228,12 @@ public class SendToMyMaps implements Runnable {
|
||||
"Using elevation sampling factor: " + elevationSamplingFrequency
|
||||
+ " on " + totalLocations);
|
||||
double totalDistance = 0;
|
||||
|
||||
|
||||
Vector<Double> distances = new Vector<Double>();
|
||||
Vector<Double> elevations = new Vector<Double>();
|
||||
DoubleBuffer elevationBuffer =
|
||||
new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
|
||||
|
||||
|
||||
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
|
||||
progressIndicator.setProgressMessage(
|
||||
R.string.progress_message_reading_track);
|
||||
@@ -238,15 +242,15 @@ public class SendToMyMaps implements Runnable {
|
||||
if (totalLocationsRead % 100 == 0) {
|
||||
updateProgress();
|
||||
}
|
||||
|
||||
|
||||
Location loc = providerUtils.createLocation(locationsCursor);
|
||||
locations.add(loc);
|
||||
|
||||
|
||||
if (totalLocationsRead == 0) {
|
||||
// Put a marker at the first point of the first valid segment:
|
||||
mapsClient.uploadMarker(mapId, track.getName(), track.getDescription(), loc, true);
|
||||
}
|
||||
|
||||
|
||||
// Add to the elevation profile.
|
||||
if (loc != null && LocationUtils.isValidLocation(loc)) {
|
||||
// All points go into the smoothing buffer...
|
||||
@@ -256,19 +260,19 @@ public class SendToMyMaps implements Runnable {
|
||||
double dist = lastLocation.distanceTo(loc);
|
||||
totalDistance += dist;
|
||||
}
|
||||
|
||||
|
||||
// ...but only a few points are really used to keep the url short.
|
||||
if (totalLocationsRead % elevationSamplingFrequency == 0) {
|
||||
distances.add(totalDistance);
|
||||
elevations.add(elevationBuffer.getAverage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If the location was not valid, it's a segment split, so make sure the
|
||||
// distance between the previous segment and the new one is not accounted
|
||||
// for in the next iteration.
|
||||
lastLocation = loc;
|
||||
|
||||
|
||||
// Every now and then, upload the accumulated points
|
||||
if (totalLocationsRead % MAX_POINTS_PER_UPLOAD
|
||||
== MAX_POINTS_PER_UPLOAD - 1) {
|
||||
@@ -276,28 +280,30 @@ public class SendToMyMaps implements Runnable {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
totalLocationsRead++;
|
||||
} while (locationsCursor.moveToNext());
|
||||
|
||||
|
||||
// Do a final upload with what's left
|
||||
if (!prepareAndUploadPoints(track, locations)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Put an end marker at the last point of the last valid segment:
|
||||
if (lastLocation != null) {
|
||||
track.setDescription("<p>" + originalDescription + "</p><p>"
|
||||
+ stringUtils.generateTrackDescription(
|
||||
track, distances, elevations)
|
||||
+ "</p>");
|
||||
return mapsClient.uploadMarker(mapId, track.getName(), track.getDescription(),
|
||||
return mapsClient.uploadMarker(mapId, track.getName(), track.getDescription(),
|
||||
lastLocation, false);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
locationsCursor.close();
|
||||
if (locationsCursor != null) {
|
||||
locationsCursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,17 +312,17 @@ public class SendToMyMaps implements Runnable {
|
||||
progressIndicator.setProgressMessage(
|
||||
R.string.progress_message_preparing_track);
|
||||
updateProgress();
|
||||
|
||||
|
||||
int numLocations = locations.size();
|
||||
if (numLocations < 2) {
|
||||
Log.d(TAG, "Not preparing/uploading too few points");
|
||||
totalLocationsUploaded += numLocations;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Prepare/pre-process the points
|
||||
ArrayList<Track> splitTracks = prepareLocations(track, locations);
|
||||
|
||||
|
||||
// Start uploading them
|
||||
progressIndicator.setProgressMessage(
|
||||
R.string.progress_message_sending_mymaps);
|
||||
@@ -330,7 +336,7 @@ public class SendToMyMaps implements Runnable {
|
||||
Log.d(TAG,
|
||||
"SendToMyMaps: Prepared feature for upload w/ "
|
||||
+ splitTrack.getLocations().size() + " points.");
|
||||
|
||||
|
||||
// Transmit tracks via GData feed:
|
||||
// -------------------------------
|
||||
Log.d(TAG,
|
||||
@@ -340,7 +346,7 @@ public class SendToMyMaps implements Runnable {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
locations.clear();
|
||||
totalLocationsUploaded += numLocations;
|
||||
updateProgress();
|
||||
@@ -358,7 +364,7 @@ public class SendToMyMaps implements Runnable {
|
||||
private ArrayList<Track> prepareLocations(
|
||||
Track track, Iterable<Location> locations) {
|
||||
ArrayList<Track> splitTracks = new ArrayList<Track>();
|
||||
|
||||
|
||||
// Create segments from each full track:
|
||||
Track segment = new Track();
|
||||
TripStatistics segmentStats = segment.getStatistics();
|
||||
@@ -377,11 +383,11 @@ public class SendToMyMaps implements Runnable {
|
||||
if (loc.getLatitude() > 90) {
|
||||
startNewTrackSegment = true;
|
||||
}
|
||||
|
||||
|
||||
if (startNewTrackSegment) {
|
||||
// Close up the last segment.
|
||||
prepareTrackSegment(segment, splitTracks);
|
||||
|
||||
|
||||
Log.d(TAG,
|
||||
"MyTracksSendToMyMaps: Starting new track segment...");
|
||||
startNewTrackSegment = false;
|
||||
@@ -391,7 +397,7 @@ public class SendToMyMaps implements Runnable {
|
||||
segment.setDescription(/* track.getDescription() */ "");
|
||||
segment.setCategory(track.getCategory());
|
||||
}
|
||||
|
||||
|
||||
if (loc.getLatitude() <= 90) {
|
||||
segment.addLocation(loc);
|
||||
if (segmentStats.getStartTime() < 0) {
|
||||
@@ -400,9 +406,9 @@ public class SendToMyMaps implements Runnable {
|
||||
}
|
||||
totalLocationsPrepared++;
|
||||
}
|
||||
|
||||
|
||||
prepareTrackSegment(segment, splitTracks);
|
||||
|
||||
|
||||
return splitTracks;
|
||||
}
|
||||
|
||||
@@ -425,13 +431,13 @@ public class SendToMyMaps implements Runnable {
|
||||
&& segment.getLocations().size() > 0) {
|
||||
segmentStats.setStopTime(segment.getLocations().size() - 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Decimate to 2 meter precision. Mapshop doesn't like too many
|
||||
* points:
|
||||
*/
|
||||
LocationUtils.decimate(segment, 2.0);
|
||||
|
||||
|
||||
/* It the track still has > 500 points, split it in pieces: */
|
||||
if (segment.getLocations().size() > 500) {
|
||||
splitTracks.addAll(LocationUtils.split(segment, 500));
|
||||
@@ -447,7 +453,7 @@ public class SendToMyMaps implements Runnable {
|
||||
// The percent of the total that represents the completed part of this
|
||||
// segment.
|
||||
int totalPercentage =
|
||||
(totalLocationsRead + totalLocationsPrepared + totalLocationsUploaded)
|
||||
(totalLocationsRead + totalLocationsPrepared + totalLocationsUploaded) * 100
|
||||
/ (totalLocations * 3);
|
||||
totalPercentage = Math.min(99, totalPercentage);
|
||||
progressIndicator.setProgressValue(totalPercentage);
|
||||
|
||||
@@ -185,7 +185,7 @@ public class BackupActivityHelper {
|
||||
*/
|
||||
private void restoreFromDateAsync(final Date date) {
|
||||
// Show a progress dialog
|
||||
final ProgressDialog progressDialog = ProgressDialog.show(
|
||||
ProgressDialog.show(
|
||||
activity,
|
||||
activity.getString(R.string.progress_title),
|
||||
activity.getString(R.string.backup_import_progress_message),
|
||||
@@ -202,8 +202,6 @@ public class BackupActivityHelper {
|
||||
Log.e(Constants.TAG, "Failed to restore backup", e);
|
||||
showToast(R.string.io_read_failed);
|
||||
} finally {
|
||||
dismissDialog(progressDialog);
|
||||
|
||||
// Data may have been restored, "reboot" the app to catch it
|
||||
restartApplication();
|
||||
}
|
||||
|
||||
@@ -80,12 +80,13 @@ class DatabaseDumper {
|
||||
*
|
||||
* @param cursor the cursor to get columns from
|
||||
* @param numRows the number of rows that will be later written
|
||||
* @param writer the output to write to
|
||||
* @throws IOException if there are errors while writing
|
||||
*/
|
||||
public void writeHeaders(Cursor cursor, int numRows, DataOutputStream writer)
|
||||
throws IOException {
|
||||
initializeCachedValues(cursor);
|
||||
writeQueryMetadata(cursor, numRows, writer);
|
||||
writeQueryMetadata(numRows, writer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,6 +94,7 @@ class DatabaseDumper {
|
||||
* This must be called after {@link #writeHeaders}.
|
||||
*
|
||||
* @param cursor the cursor to write data from
|
||||
* @param writer the output to write to
|
||||
* @throws IOException if there are any errors while writing
|
||||
*/
|
||||
public void writeOneRow(Cursor cursor, DataOutputStream writer)
|
||||
@@ -146,12 +148,12 @@ class DatabaseDumper {
|
||||
/**
|
||||
* Writes metadata about the query to be dumped.
|
||||
*
|
||||
* @param cursor the cursor that the data will come from
|
||||
* @param numRows the number of rows that will be dumped
|
||||
* @param writer the output to write to
|
||||
* @throws IOException if there are any errors while writing
|
||||
*/
|
||||
private void writeQueryMetadata(
|
||||
Cursor cursor, int numRows, DataOutputStream writer) throws IOException {
|
||||
int numRows, DataOutputStream writer) throws IOException {
|
||||
// Write column data
|
||||
writer.writeInt(columnNames.length);
|
||||
for (int i = 0; i < columnNames.length; i++) {
|
||||
@@ -171,6 +173,7 @@ class DatabaseDumper {
|
||||
* @param columnIdx the column index to read from
|
||||
* @param columnTypeId the type of the column to be read
|
||||
* @param cursor the cursor to read from
|
||||
* @param writer the output to write to
|
||||
* @throws IOException if there are any errors while writing
|
||||
*/
|
||||
private void writeCell(
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.backup;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.content.TrackPointsColumns;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
@@ -205,7 +207,9 @@ class ExternalFileBackup {
|
||||
} catch (IOException e) {
|
||||
// We tried to delete the partially created file, but do nothing
|
||||
// if that also fails.
|
||||
outputFile.delete();
|
||||
if (!outputFile.delete()) {
|
||||
Log.w(TAG, "Failed to delete file " + outputFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
throw e;
|
||||
} finally {
|
||||
|
||||
@@ -69,22 +69,22 @@ public class DocsHelper {
|
||||
private static final String OPENDOCUMENT_SPREADSHEET_MIME_TYPE =
|
||||
"application/x-vnd.oasis.opendocument.spreadsheet";
|
||||
private static final String ATOM_FEED_MIME_TYPE = "application/atom+xml";
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new MyTracks spreadsheet with the given name.
|
||||
*
|
||||
*
|
||||
* @param context The context associated with this request.
|
||||
* @param docListWrapper The GData handle for the Document List service.
|
||||
* @param name The name for the newly-created spreadsheet.
|
||||
* @return The spreadsheet ID, if one is created. {@code null} will be
|
||||
* returned if a GData error didn't occur, but no spreadsheet ID was
|
||||
* returned.
|
||||
* returned.
|
||||
*/
|
||||
public String createSpreadsheet(final Context context,
|
||||
public String createSpreadsheet(final Context context,
|
||||
final GDataWrapper<GDataServiceClient> docListWrapper, final String name) throws IOException {
|
||||
final AtomicReference<String> idSaver = new AtomicReference<String>();
|
||||
|
||||
boolean result = docListWrapper.runQuery(new QueryFunction<GDataServiceClient>() {
|
||||
boolean success = docListWrapper.runQuery(new QueryFunction<GDataServiceClient>() {
|
||||
@Override
|
||||
public void query(GDataServiceClient client) throws IOException,
|
||||
GDataWrapper.AuthenticationException {
|
||||
@@ -95,7 +95,7 @@ public class DocsHelper {
|
||||
OPENDOCUMENT_SPREADSHEET_MIME_TYPE);
|
||||
conn.addRequestProperty("Slug", name);
|
||||
conn.addRequestProperty("Authorization",
|
||||
"GoogleLogin auth=" +
|
||||
"GoogleLogin auth=" +
|
||||
docListWrapper.getAuthManager().getAuthToken());
|
||||
conn.setDoOutput(true);
|
||||
OutputStream os = conn.getOutputStream();
|
||||
@@ -141,24 +141,24 @@ public class DocsHelper {
|
||||
if (idStringStart == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
String id = result.substring(
|
||||
idStringStart + DOCS_SPREADSHEET_URL.length(), idTagCloseIndex);
|
||||
Log.i(Constants.TAG, "Created new spreadsheet: " + id);
|
||||
idSaver.set(id);
|
||||
}});
|
||||
|
||||
if (!result) {
|
||||
throw newIOException(docListWrapper,
|
||||
|
||||
if (!success) {
|
||||
throw newIOException(docListWrapper,
|
||||
"Failed to create new spreadsheet.");
|
||||
}
|
||||
|
||||
|
||||
return idSaver.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the ID of a spreadsheet with the given name.
|
||||
*
|
||||
*
|
||||
* @param docListWrapper The GData handle for the Document List service.
|
||||
* @param title The name of the spreadsheet whose ID is to be retrieved.
|
||||
* @return The spreadsheet ID, if it can be retrieved. {@code null} will
|
||||
@@ -177,7 +177,7 @@ public class DocsHelper {
|
||||
GDataParser listParser;
|
||||
try {
|
||||
listParser = client.getParserForFeed(Entry.class,
|
||||
DOCS_MY_SPREADSHEETS_FEED_URL,
|
||||
DOCS_MY_SPREADSHEETS_FEED_URL,
|
||||
docListWrapper.getAuthManager().getAuthToken());
|
||||
listParser.init();
|
||||
|
||||
@@ -201,22 +201,22 @@ public class DocsHelper {
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
throw newIOException(docListWrapper,
|
||||
throw newIOException(docListWrapper,
|
||||
"Failed to retrieve spreadsheet list.");
|
||||
}
|
||||
|
||||
|
||||
return idSaver.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the ID of the first worksheet in the named spreadsheet.
|
||||
*
|
||||
*
|
||||
* @param trixWrapper The GData handle for the spreadsheet service.
|
||||
* @param spreadsheetId The GData ID for the given spreadsheet.
|
||||
* @return The worksheet ID, if it can be retrieved. {@code null} will be
|
||||
* returned if the GData request returns without error, but without an
|
||||
* ID.
|
||||
* @throws IOException If an error occurs during the GData request.
|
||||
* @throws IOException If an error occurs during the GData request.
|
||||
*/
|
||||
public String getWorksheetId(final GDataWrapper<GDataServiceClient> trixWrapper,
|
||||
final String spreadsheetId) throws IOException {
|
||||
@@ -250,17 +250,17 @@ public class DocsHelper {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (!result) {
|
||||
throw newIOException(trixWrapper, "Failed to retrieve worksheet ID.");
|
||||
}
|
||||
|
||||
|
||||
return idSaver.get();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a row to a worksheet containing the stats for a given track.
|
||||
*
|
||||
*
|
||||
* @param context The context associated with this request.
|
||||
* @param trixAuth The GData authorization for the spreadsheet service.
|
||||
* @param spreadsheetId The spreadsheet to be modified.
|
||||
@@ -270,17 +270,17 @@ public class DocsHelper {
|
||||
* imperial units will be used.
|
||||
* @throws IOException If an error occurs while updating the worksheet.
|
||||
*/
|
||||
public void addTrackRow(Context context, AuthManager trixAuth,
|
||||
String spreadsheetId, String worksheetId, Track track,
|
||||
public void addTrackRow(Context context, AuthManager trixAuth,
|
||||
String spreadsheetId, String worksheetId, Track track,
|
||||
boolean metricUnits) throws IOException {
|
||||
|
||||
|
||||
String worksheetUri = String.format(DOCS_SPREADSHEET_URL_FORMAT,
|
||||
spreadsheetId, worksheetId);
|
||||
TripStatistics stats = track.getStatistics();
|
||||
|
||||
String distanceUnit = context.getString(metricUnits ?
|
||||
|
||||
String distanceUnit = context.getString(metricUnits ?
|
||||
R.string.kilometer : R.string.mile);
|
||||
String speedUnit = context.getString(metricUnits ?
|
||||
String speedUnit = context.getString(metricUnits ?
|
||||
R.string.kilometer_per_hour : R.string.mile_per_hour);
|
||||
String elevationUnit = context.getString(metricUnits ?
|
||||
R.string.meter : R.string.feet);
|
||||
@@ -310,7 +310,7 @@ public class DocsHelper {
|
||||
tagBuilder.append("map", String.format("%s?msa=0&msid=%s",
|
||||
Constants.MAPSHOP_BASE_URL, track.getMapId()));
|
||||
}
|
||||
|
||||
|
||||
String postText = new StringBuilder()
|
||||
.append("<entry xmlns='http://www.w3.org/2005/Atom' "
|
||||
+ "xmlns:gsx='http://schemas.google.com/spreadsheets/"
|
||||
@@ -323,7 +323,7 @@ public class DocsHelper {
|
||||
"Inserting at: " + spreadsheetId + " => " + worksheetUri);
|
||||
|
||||
Log.i(Constants.TAG, postText);
|
||||
|
||||
|
||||
writeRowData(trixAuth, worksheetUri, postText);
|
||||
|
||||
Log.i(Constants.TAG, "Post finished.");
|
||||
@@ -331,13 +331,13 @@ public class DocsHelper {
|
||||
|
||||
/**
|
||||
* Writes spreadsheet row data to the indicated worksheet.
|
||||
*
|
||||
*
|
||||
* @param trixAuth The GData authorization for the spreadsheet service.
|
||||
* @param worksheetUri The URI of the worksheet to be altered.
|
||||
* @param postText The XML tags describing the change to be made.
|
||||
* @throws IOException Thrown if an error occurs during the write.
|
||||
*/
|
||||
protected void writeRowData(AuthManager trixAuth, String worksheetUri,
|
||||
protected void writeRowData(AuthManager trixAuth, String worksheetUri,
|
||||
String postText) throws IOException {
|
||||
// No need for a wrapper because we know that the authorization was good
|
||||
// enough to get this far.
|
||||
@@ -364,9 +364,9 @@ public class DocsHelper {
|
||||
rd.close();
|
||||
}
|
||||
|
||||
private static IOException newIOException(GDataWrapper<GDataServiceClient> wrapper,
|
||||
private static IOException newIOException(GDataWrapper<GDataServiceClient> wrapper,
|
||||
String message) {
|
||||
return new IOException(String.format("%s: %d: %s", message,
|
||||
return new IOException(String.format("%s: %d: %s", message,
|
||||
wrapper.getErrorType(), wrapper.getErrorMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -51,7 +51,7 @@ public class CsvTrackWriter implements TrackFormatWriter {
|
||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
|
||||
static {
|
||||
SHORT_FORMAT.setMaximumFractionDigits(4);
|
||||
SHORT_FORMAT.setMaximumFractionDigits(4);
|
||||
TIMESTAMP_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ public class CsvTrackWriter implements TrackFormatWriter {
|
||||
return TrackFileFormat.CSV.getExtension();
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
@Override
|
||||
public void prepare(Track track, OutputStream out) {
|
||||
this.track = track;
|
||||
|
||||
@@ -67,6 +67,7 @@ public class GpxTrackWriter implements TrackFormatWriter {
|
||||
+ "\" lon=\"" + coordinateFormatter.format(l.getLongitude()) + "\"";
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
@Override
|
||||
public void prepare(Track track, OutputStream out) {
|
||||
this.track = track;
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.util.UriUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ContentUris;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Helper activity which imports tracks from a file.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class ImportActivity extends Activity {
|
||||
|
||||
private static final int PROGRESS_DIALOG = 1;
|
||||
private static final int SUCCESS_DIALOG = 2;
|
||||
private static final int FAILURE_DIALOG = 3;
|
||||
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
|
||||
private ProgressDialog progressDialog;
|
||||
private int resultMessage;
|
||||
private long importedTrackIds[];
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedState) {
|
||||
super.onCreate(savedState);
|
||||
|
||||
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
Intent intent = getIntent();
|
||||
String action = intent.getAction();
|
||||
Uri data = intent.getData();
|
||||
if (!(Intent.ACTION_VIEW.equals(action) || Intent.ACTION_ATTACH_DATA.equals(action))
|
||||
|| !UriUtils.isFileUri(data)) {
|
||||
Log.e(TAG, "Received an intent with unsupported action or data: " + intent);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(TAG, "Importing GPX file at " + data);
|
||||
startTrackImport(data.getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
switch (id) {
|
||||
case PROGRESS_DIALOG:
|
||||
progressDialog = new ProgressDialog(this);
|
||||
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||
progressDialog.setTitle(R.string.progress_title);
|
||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
progressDialog.setMessage(getString(R.string.import_progress_message));
|
||||
return progressDialog;
|
||||
case SUCCESS_DIALOG:
|
||||
final Builder dialogBuilder = new AlertDialog.Builder(this);
|
||||
dialogBuilder.setCancelable(true);
|
||||
dialogBuilder.setPositiveButton(android.R.string.ok, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface arg0, int arg1) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
dialogBuilder.setNeutralButton(R.string.import_show_track, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface arg0, int arg1) {
|
||||
showImportedTrack();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
return dialogBuilder.create();
|
||||
case FAILURE_DIALOG:
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setNeutralButton(R.string.ok, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface arg0, int arg1) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
builder.setTitle(R.string.error);
|
||||
return builder.create();
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPrepareDialog(int id, Dialog dialog) {
|
||||
super.onPrepareDialog(id, dialog);
|
||||
|
||||
switch (id) {
|
||||
case SUCCESS_DIALOG:
|
||||
AlertDialog successDialog = (AlertDialog) dialog;
|
||||
successDialog.setMessage(getString(R.string.import_success, importedTrackIds.length));
|
||||
break;
|
||||
case FAILURE_DIALOG:
|
||||
AlertDialog failureDialog = (AlertDialog) dialog;
|
||||
failureDialog.setMessage(getString(resultMessage));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void showImportedTrack() {
|
||||
long lastTrackId = importedTrackIds[importedTrackIds.length - 1];
|
||||
Uri trackUri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, lastTrackId);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(trackUri, TracksColumns.CONTENT_ITEMTYPE);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void startTrackImport(final String fileName) {
|
||||
showDialog(PROGRESS_DIALOG);
|
||||
|
||||
Thread t = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
resultMessage = R.string.success;
|
||||
|
||||
importedTrackIds = null;
|
||||
|
||||
try {
|
||||
try {
|
||||
InputStream is = new FileInputStream(fileName);
|
||||
importedTrackIds = GpxImporter.importGPXFile(is, providerUtils);
|
||||
} catch (SAXException e) {
|
||||
Log.e(TAG, "Caught an unexpected exception.", e);
|
||||
resultMessage = R.string.error_generic;
|
||||
} catch (ParserConfigurationException e) {
|
||||
Log.e(TAG, "Caught an unexpected exception.", e);
|
||||
resultMessage = R.string.error_generic;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Caught an unexpected exception.", e);
|
||||
resultMessage = R.string.error_unable_to_read_file;
|
||||
} catch (NullPointerException e) {
|
||||
Log.e(TAG, "Caught an unexpected exception.", e);
|
||||
resultMessage = R.string.error_invalid_gpx_format;
|
||||
} catch (OutOfMemoryError e) {
|
||||
Log.e(TAG, "Caught an unexpected exception.", e);
|
||||
resultMessage = R.string.error_out_of_memory;
|
||||
}
|
||||
|
||||
boolean success = (importedTrackIds != null && importedTrackIds.length > 0);
|
||||
showImportResult(success);
|
||||
} finally {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
dismissDialog(PROGRESS_DIALOG);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void showImportResult(boolean success) {
|
||||
final int dialogToShow = success ? SUCCESS_DIALOG : FAILURE_DIALOG;
|
||||
|
||||
// Show a dialog telling the user about the import, and asking if he wishes
|
||||
// to open the track right away.
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showDialog(dialogToShow);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -52,6 +52,7 @@ public class KmlTrackWriter implements TrackFormatWriter {
|
||||
this.stringUtils = stringUtils;
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
@Override
|
||||
public void prepare(Track track, OutputStream out) {
|
||||
this.track = track;
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
|
||||
import com.google.android.apps.mytracks.util.FileUtils;
|
||||
import com.google.android.apps.mytracks.util.UriUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnCancelListener;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Activity for saving a track to a file (and optionally sending that file).
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class SaveActivity extends Activity {
|
||||
public static final String EXTRA_SHARE_FILE = "share_file";
|
||||
public static final String EXTRA_FILE_FORMAT = "file_format";
|
||||
private static final int RESULT_DIALOG = 1;
|
||||
/* VisibleForTesting */
|
||||
static final int PROGRESS_DIALOG = 2;
|
||||
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
private long trackId;
|
||||
private TrackWriter writer;
|
||||
private boolean shareFile;
|
||||
private TrackFileFormat format;
|
||||
private WriteProgressController controller;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
|
||||
Intent intent = getIntent();
|
||||
String action = intent.getAction();
|
||||
String type = intent.getType();
|
||||
Uri data = intent.getData();
|
||||
if (!getString(R.string.save_intent_action).equals(action) ||
|
||||
!TracksColumns.CONTENT_ITEMTYPE.equals(type) ||
|
||||
!UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
|
||||
Log.e(TAG, "Got bad save intent: " + intent);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
trackId = ContentUris.parseId(data);
|
||||
|
||||
int formatIdx = intent.getIntExtra(EXTRA_FILE_FORMAT, -1);
|
||||
format = TrackFileFormat.values()[formatIdx];
|
||||
shareFile = intent.getBooleanExtra(EXTRA_SHARE_FILE, false);
|
||||
|
||||
writer = TrackWriterFactory.newWriter(this, providerUtils, trackId, format);
|
||||
if (writer == null) {
|
||||
Log.e(TAG, "Unable to build writer");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
if (shareFile) {
|
||||
// If the file is for sending, save it to a temporary location instead.
|
||||
FileUtils fileUtils = new FileUtils();
|
||||
String extension = format.getExtension();
|
||||
String dirName = fileUtils.buildExternalDirectoryPath(extension, "tmp");
|
||||
|
||||
File dir = new File(dirName);
|
||||
writer.setDirectory(dir);
|
||||
}
|
||||
|
||||
controller = new WriteProgressController(this, writer, PROGRESS_DIALOG);
|
||||
controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
onWriteComplete();
|
||||
}
|
||||
});
|
||||
controller.startWrite();
|
||||
}
|
||||
|
||||
private void onWriteComplete() {
|
||||
if (shareFile) {
|
||||
shareWrittenFile();
|
||||
} else {
|
||||
showResultDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private void shareWrittenFile() {
|
||||
if (!writer.wasSuccess()) {
|
||||
showResultDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
// Share the file.
|
||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
|
||||
getResources().getText(R.string.send_track_subject).toString());
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT,
|
||||
getResources().getText(R.string.send_track_body_format)
|
||||
.toString());
|
||||
shareIntent.setType(format.getMimeType());
|
||||
Uri u = Uri.fromFile(new File(writer.getAbsolutePath()));
|
||||
shareIntent.putExtra(Intent.EXTRA_STREAM, u);
|
||||
startActivity(Intent.createChooser(shareIntent,
|
||||
getResources().getText(R.string.share_track).toString()));
|
||||
}
|
||||
|
||||
private void showResultDialog() {
|
||||
removeDialog(RESULT_DIALOG);
|
||||
showDialog(RESULT_DIALOG);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
switch (id) {
|
||||
case RESULT_DIALOG:
|
||||
return createResultDialog();
|
||||
case PROGRESS_DIALOG:
|
||||
if (controller != null) {
|
||||
return controller.createProgressDialog();
|
||||
}
|
||||
//$FALL-THROUGH$
|
||||
default:
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
}
|
||||
|
||||
private Dialog createResultDialog() {
|
||||
boolean success = writer.wasSuccess();
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setMessage(writer.getErrorMessage());
|
||||
builder.setNeutralButton(R.string.ok, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int arg1) {
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
builder.setOnCancelListener(new OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
builder.setIcon(success ? android.R.drawable.ic_dialog_info :
|
||||
android.R.drawable.ic_dialog_alert);
|
||||
builder.setTitle(success ? R.string.success : R.string.error);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
public static void handleExportTrackAction(Context ctx, long trackId, int actionCode) {
|
||||
if (trackId < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
TrackFileFormat exportFormat = null;
|
||||
switch (actionCode) {
|
||||
case Constants.SAVE_GPX_FILE:
|
||||
case Constants.SHARE_GPX_FILE:
|
||||
exportFormat = TrackFileFormat.GPX;
|
||||
break;
|
||||
case Constants.SAVE_KML_FILE:
|
||||
case Constants.SHARE_KML_FILE:
|
||||
exportFormat = TrackFileFormat.KML;
|
||||
break;
|
||||
case Constants.SAVE_CSV_FILE:
|
||||
case Constants.SHARE_CSV_FILE:
|
||||
exportFormat = TrackFileFormat.CSV;
|
||||
break;
|
||||
case Constants.SAVE_TCX_FILE:
|
||||
case Constants.SHARE_TCX_FILE:
|
||||
exportFormat = TrackFileFormat.TCX;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Warning unhandled action code: " + actionCode);
|
||||
}
|
||||
|
||||
boolean shareFile = false;
|
||||
switch (actionCode) {
|
||||
case Constants.SHARE_GPX_FILE:
|
||||
case Constants.SHARE_KML_FILE:
|
||||
case Constants.SHARE_CSV_FILE:
|
||||
case Constants.SHARE_TCX_FILE:
|
||||
shareFile = true;
|
||||
}
|
||||
|
||||
Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
|
||||
|
||||
Intent intent = new Intent(ctx, SaveActivity.class);
|
||||
intent.setAction(ctx.getString(R.string.save_intent_action));
|
||||
intent.setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
|
||||
intent.putExtra(EXTRA_FILE_FORMAT, exportFormat.ordinal());
|
||||
intent.putExtra(EXTRA_SHARE_FILE, shareFile);
|
||||
ctx.startActivity(intent);
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
||||
timestampFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
@Override
|
||||
public void prepare(Track track, OutputStream out) {
|
||||
this.track = track;
|
||||
@@ -187,7 +188,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
||||
&& sensorData.getCadence().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorData.getCadence().hasValue()) {
|
||||
pw.print(" <Cadence>");
|
||||
pw.print(sensorData.getCadence().getValue());
|
||||
pw.print(Math.min(254, sensorData.getCadence().getValue()));
|
||||
pw.println("</Cadence>");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -24,18 +27,18 @@ import java.io.File;
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class TempFileCleaner {
|
||||
|
||||
|
||||
private long currentTimeMillis;
|
||||
|
||||
public static void clean() {
|
||||
(new TempFileCleaner(System.currentTimeMillis())).cleanImpl();
|
||||
}
|
||||
|
||||
|
||||
// @VisibleForTesting
|
||||
TempFileCleaner(long time) {
|
||||
currentTimeMillis = time;
|
||||
}
|
||||
|
||||
|
||||
private void cleanImpl() {
|
||||
if (!Environment.getExternalStorageState().equals(
|
||||
Environment.MEDIA_MOUNTED)) {
|
||||
@@ -64,7 +67,9 @@ public class TempFileCleaner {
|
||||
long oldest = currentTimeMillis - 1000 * 3600;
|
||||
for (File f : dir.listFiles()) {
|
||||
if (f.lastModified() < oldest) {
|
||||
f.delete();
|
||||
if (!f.delete()) {
|
||||
Log.w(TAG, "Failed to delete file " + f.getAbsolutePath());
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* A factory to produce track writers for any format.
|
||||
@@ -90,6 +93,11 @@ public class TrackWriterFactory {
|
||||
MyTracksProviderUtils providerUtils,
|
||||
long trackId, TrackFileFormat format) {
|
||||
Track track = providerUtils.getTrack(trackId);
|
||||
if (track == null) {
|
||||
Log.w(TAG, "Trying to create a writer for an invalid track, id=" + trackId);
|
||||
return null;
|
||||
}
|
||||
|
||||
return newWriter(context, providerUtils, track, format);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
@@ -120,7 +122,9 @@ class TrackWriterImpl implements TrackWriter {
|
||||
} catch (InterruptedException e) {
|
||||
Log.i(Constants.TAG, "The track write was interrupted");
|
||||
if (file != null) {
|
||||
file.delete();
|
||||
if (!file.delete()) {
|
||||
Log.w(TAG, "Failed to delete file " + file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
success = false;
|
||||
errorMessage = R.string.error_operation_cancelled;
|
||||
@@ -195,7 +199,7 @@ class TrackWriterImpl implements TrackWriter {
|
||||
directory, track.getName(), writer.getExtension());
|
||||
if (fileName == null) {
|
||||
Log.e(Constants.TAG,
|
||||
"Unable to get a unique filename for " + fileName);
|
||||
"Unable to get a unique filename for " + track.getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -276,9 +280,7 @@ class TrackWriterImpl implements TrackWriter {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-17
@@ -13,9 +13,8 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks;
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import com.google.android.apps.mytracks.io.file.TrackWriter;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Activity;
|
||||
@@ -41,14 +40,15 @@ class WriteProgressController {
|
||||
* dialog has been dismissed. Whether the write succeeded can be
|
||||
* determined by examining the {@link TrackWriter}.
|
||||
*/
|
||||
public void onComplete(TrackWriter writer);
|
||||
public void onComplete();
|
||||
}
|
||||
|
||||
private final Activity activity;
|
||||
private final TrackWriter writer;
|
||||
private final ProgressDialog dialog;
|
||||
private ProgressDialog dialog;
|
||||
|
||||
private OnCompletionListener onCompletionListener;
|
||||
private final int progressDialogId;
|
||||
|
||||
/**
|
||||
* @param activity the activity associated with this write
|
||||
@@ -57,17 +57,10 @@ class WriteProgressController {
|
||||
* interested in notification upon completion of the write, they should
|
||||
* use {@link #setOnCompletionListener}.
|
||||
*/
|
||||
public WriteProgressController(Activity activity, TrackWriter writer) {
|
||||
public WriteProgressController(Activity activity, TrackWriter writer, int progressDialogId) {
|
||||
this.activity = activity;
|
||||
this.writer = writer;
|
||||
|
||||
dialog = new ProgressDialog(activity);
|
||||
dialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||
dialog.setTitle(activity.getString(R.string.progress_title));
|
||||
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
dialog.setMessage(activity.getString(R.string.write_progress_message));
|
||||
dialog.setIndeterminate(true);
|
||||
dialog.setOnCancelListener(dialogCancelListener);
|
||||
this.progressDialogId = progressDialogId;
|
||||
|
||||
writer.setOnCompletionListener(writerCompleteListener);
|
||||
writer.setOnWriteListener(writerWriteListener);
|
||||
@@ -78,9 +71,20 @@ class WriteProgressController {
|
||||
this.onCompletionListener = onCompletionListener;
|
||||
}
|
||||
|
||||
public ProgressDialog createProgressDialog() {
|
||||
dialog = new ProgressDialog(activity);
|
||||
dialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||
dialog.setTitle(activity.getString(R.string.progress_title));
|
||||
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
dialog.setMessage(activity.getString(R.string.write_progress_message));
|
||||
dialog.setIndeterminate(true);
|
||||
dialog.setOnCancelListener(dialogCancelListener);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/** Initiate an asynchronous write. */
|
||||
public void startWrite() {
|
||||
DialogManager.showDialogSafely(activity, dialog);
|
||||
activity.showDialog(progressDialogId);
|
||||
writer.writeTrackAsync();
|
||||
}
|
||||
|
||||
@@ -92,7 +96,7 @@ class WriteProgressController {
|
||||
private final DialogInterface.OnCancelListener dialogCancelListener =
|
||||
new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
public void onCancel(DialogInterface dialogInterface) {
|
||||
writer.stopWriteTrack();
|
||||
}
|
||||
};
|
||||
@@ -101,10 +105,10 @@ class WriteProgressController {
|
||||
new TrackWriter.OnCompletionListener() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
DialogManager.dismissDialogSafely(activity, dialog);
|
||||
activity.dismissDialog(progressDialogId);
|
||||
|
||||
if (onCompletionListener != null) {
|
||||
onCompletionListener.onComplete(writer);
|
||||
onCompletionListener.onComplete();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -137,7 +137,7 @@ public class AndroidGDataClient implements GDataClient {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see GDataClient#encodeUri(java.lang.String)
|
||||
*/
|
||||
public String encodeUri(String uri) {
|
||||
@@ -155,7 +155,7 @@ public class AndroidGDataClient implements GDataClient {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see com.google.wireless.gdata.client.GDataClient#createQueryParams()
|
||||
*/
|
||||
public QueryParams createQueryParams() {
|
||||
@@ -273,7 +273,7 @@ public class AndroidGDataClient implements GDataClient {
|
||||
String errorMessage = null;
|
||||
HttpEntity entity = response.getEntity();
|
||||
try {
|
||||
if (response != null && entity != null) {
|
||||
if (entity != null) {
|
||||
InputStream in = entity.getContent();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buf = new byte[8192];
|
||||
@@ -329,7 +329,7 @@ public class AndroidGDataClient implements GDataClient {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see GDataClient#getFeedAsStream(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public InputStream getFeedAsStream(String feedUrl, String authToken)
|
||||
@@ -358,7 +358,7 @@ public class AndroidGDataClient implements GDataClient {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see GDataClient#createEntry
|
||||
*/
|
||||
public InputStream createEntry(String feedUrl, String authToken,
|
||||
@@ -377,7 +377,7 @@ public class AndroidGDataClient implements GDataClient {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see GDataClient#updateEntry
|
||||
*/
|
||||
public InputStream updateEntry(String editUri, String authToken,
|
||||
@@ -395,7 +395,7 @@ public class AndroidGDataClient implements GDataClient {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see GDataClient#deleteEntry
|
||||
*/
|
||||
public void deleteEntry(String editUri, String authToken)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -17,6 +17,7 @@ package com.google.android.apps.mytracks.io.gdata;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.io.AuthManager;
|
||||
import com.google.android.apps.mytracks.io.AuthManager.AuthCallback;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
@@ -26,6 +27,7 @@ import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
||||
/**
|
||||
@@ -132,7 +134,7 @@ public class GDataWrapper<C> {
|
||||
public static final int ERROR_CLEANED_UP = 7;
|
||||
// An unknown error occurred.
|
||||
public static final int ERROR_UNKNOWN = 100;
|
||||
|
||||
|
||||
private static final int AUTH_TOKEN_INVALIDATE_REFRESH_NUM_RETRIES = 1;
|
||||
private static final int AUTH_TOKEN_INVALIDATE_REFRESH_TIMEOUT = 5000;
|
||||
|
||||
@@ -141,7 +143,7 @@ public class GDataWrapper<C> {
|
||||
private C gdataServiceClient;
|
||||
private AuthManager auth;
|
||||
private boolean retryOnAuthFailure;
|
||||
|
||||
|
||||
public GDataWrapper() {
|
||||
errorType = ERROR_NO_ERROR;
|
||||
errorMessage = null;
|
||||
@@ -179,7 +181,7 @@ public class GDataWrapper<C> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Log.d(Constants.TAG, "retrying function/query");
|
||||
}
|
||||
return false;
|
||||
@@ -189,7 +191,7 @@ public class GDataWrapper<C> {
|
||||
* Execute a given function or query. If one is executed, errorType and
|
||||
* errorMessage will contain the result/status of the function/query.
|
||||
*/
|
||||
private void runOne(final AuthenticatedFunction function,
|
||||
private void runOne(final AuthenticatedFunction function,
|
||||
final QueryFunction<C> query) {
|
||||
try {
|
||||
if (function != null) {
|
||||
@@ -210,7 +212,7 @@ public class GDataWrapper<C> {
|
||||
errorType = ERROR_AUTH;
|
||||
errorMessage = e.getMessage();
|
||||
} catch (HttpException e) {
|
||||
Log.e(Constants.TAG,
|
||||
Log.e(Constants.TAG,
|
||||
"HttpException, code " + e.getStatusCode() + " message " + e.getMessage(), e);
|
||||
errorMessage = e.getMessage();
|
||||
if (e.getStatusCode() == 401) {
|
||||
@@ -241,10 +243,10 @@ public class GDataWrapper<C> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Invalidates and refreshes the auth token. Blocks until the refresh has
|
||||
* completed or until we deem the refresh as having timed out.
|
||||
*
|
||||
*
|
||||
* @return true If the invalidate/refresh succeeds, false if it fails or
|
||||
* times out.
|
||||
*/
|
||||
@@ -252,19 +254,26 @@ public class GDataWrapper<C> {
|
||||
Log.d(Constants.TAG, "Retrying due to auth failure");
|
||||
// This FutureTask doesn't do anything -- it exists simply to be
|
||||
// blocked upon using get().
|
||||
FutureTask<?> whenFinishedFuture = new FutureTask<Object>(new Runnable() {
|
||||
final FutureTask<?> whenFinishedFuture = new FutureTask<Object>(new Runnable() {
|
||||
public void run() {}
|
||||
}, null);
|
||||
|
||||
auth.invalidateAndRefresh(whenFinishedFuture);
|
||||
final AtomicBoolean finalSuccess = new AtomicBoolean(false);
|
||||
auth.invalidateAndRefresh(new AuthCallback() {
|
||||
@Override
|
||||
public void onAuthResult(boolean success) {
|
||||
finalSuccess.set(success);
|
||||
whenFinishedFuture.run();
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
Log.d(Constants.TAG, "waiting for invalidate");
|
||||
whenFinishedFuture.get(AUTH_TOKEN_INVALIDATE_REFRESH_TIMEOUT,
|
||||
whenFinishedFuture.get(AUTH_TOKEN_INVALIDATE_REFRESH_TIMEOUT,
|
||||
TimeUnit.MILLISECONDS);
|
||||
Log.d(Constants.TAG, "invalidate finished");
|
||||
return true;
|
||||
|
||||
boolean success = finalSuccess.get();
|
||||
Log.d(Constants.TAG, "invalidate finished, success = " + success);
|
||||
return success;
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(Constants.TAG, "Failed to invalidate", e);
|
||||
} catch (ExecutionException e) {
|
||||
@@ -274,7 +283,7 @@ public class GDataWrapper<C> {
|
||||
} finally {
|
||||
whenFinishedFuture.cancel(false);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -289,11 +298,11 @@ public class GDataWrapper<C> {
|
||||
public void setAuthManager(AuthManager auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
|
||||
public AuthManager getAuthManager() {
|
||||
return auth;
|
||||
}
|
||||
|
||||
|
||||
public void setRetryOnAuthFailure(boolean retry) {
|
||||
retryOnAuthFailure = retry;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.google.android.apps.mytracks.io.mymaps;
|
||||
|
||||
import com.google.android.maps.GeoPoint;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Random;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
@@ -12,7 +12,7 @@ import java.util.Vector;
|
||||
* {@link MyMapsFeatureMetadata} object so that it can be more efficiently
|
||||
* transmitted to other activities.
|
||||
*/
|
||||
class MyMapsFeature implements Serializable {
|
||||
class MyMapsFeature {
|
||||
|
||||
private static final long serialVersionUID = 8439035544430497236L;
|
||||
|
||||
@@ -49,6 +49,8 @@ class MyMapsFeature implements Serializable {
|
||||
/** The metadata of this feature in a format efficient for transmission. */
|
||||
private MyMapsFeatureMetadata featureInfo = new MyMapsFeatureMetadata();
|
||||
|
||||
private final Random random = new Random();
|
||||
|
||||
/**
|
||||
* Initializes a valid but empty feature. It will default to a
|
||||
* {@link #MARKER} with a blue placemark with a dot as an icon at the
|
||||
@@ -62,7 +64,7 @@ class MyMapsFeature implements Serializable {
|
||||
*
|
||||
* @param point The new point to add
|
||||
*/
|
||||
public synchronized void addPoint(GeoPoint point) {
|
||||
public void addPoint(GeoPoint point) {
|
||||
latitudeE6.add(point.getLatitudeE6());
|
||||
longitudeE6.add(point.getLongitudeE6());
|
||||
}
|
||||
@@ -71,10 +73,10 @@ class MyMapsFeature implements Serializable {
|
||||
* Generates a new local id for this feature based on the current time and
|
||||
* a random number.
|
||||
*/
|
||||
public synchronized void generateAndroidId() {
|
||||
Long time = System.currentTimeMillis();
|
||||
Integer random = (int) (Math.random() * 10000);
|
||||
androidId = time.toString() + "." + random.toString();
|
||||
void generateAndroidId() {
|
||||
long time = System.currentTimeMillis();
|
||||
int rand = random.nextInt(10000);
|
||||
androidId = time + "." + rand;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +84,7 @@ class MyMapsFeature implements Serializable {
|
||||
*
|
||||
* @return The local id for this feature
|
||||
*/
|
||||
public String getAndroidId() {
|
||||
String getAndroidId() {
|
||||
return androidId;
|
||||
}
|
||||
|
||||
@@ -102,7 +104,7 @@ class MyMapsFeature implements Serializable {
|
||||
*
|
||||
* @param description The new description of this feature
|
||||
*/
|
||||
public synchronized void setDescription(String description) {
|
||||
public void setDescription(String description) {
|
||||
featureInfo.setDescription(description);
|
||||
}
|
||||
|
||||
@@ -196,7 +198,7 @@ class MyMapsFeature implements Serializable {
|
||||
*
|
||||
* @param title The new title of this feature
|
||||
*/
|
||||
public synchronized void setTitle(String title) {
|
||||
public void setTitle(String title) {
|
||||
featureInfo.setTitle(title);
|
||||
}
|
||||
|
||||
@@ -207,7 +209,7 @@ class MyMapsFeature implements Serializable {
|
||||
* @param type The new type of the feature. That type must be one of
|
||||
* {@link #MARKER}, {@link #LINE}, or {@link #SHAPE}
|
||||
*/
|
||||
public synchronized void setType(int type) {
|
||||
public void setType(int type) {
|
||||
featureInfo.setType(type);
|
||||
}
|
||||
|
||||
@@ -217,7 +219,7 @@ class MyMapsFeature implements Serializable {
|
||||
*
|
||||
* @param color The new ARGB color of this feature
|
||||
*/
|
||||
public synchronized void setColor(int color) {
|
||||
public void setColor(int color) {
|
||||
featureInfo.setColor(color);
|
||||
}
|
||||
|
||||
@@ -227,7 +229,7 @@ class MyMapsFeature implements Serializable {
|
||||
*
|
||||
* @param url The new icon url of the feature
|
||||
*/
|
||||
public synchronized void setIconUrl(String url) {
|
||||
public void setIconUrl(String url) {
|
||||
featureInfo.setIconUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,6 @@ class MyMapsFeatureMetadata {
|
||||
}
|
||||
|
||||
public void setIconUrl(String url) {
|
||||
iconUrl = new String(url);
|
||||
iconUrl = url;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.google.android.apps.mytracks.io.mymaps;
|
||||
|
||||
import com.google.android.apps.mytracks.io.AuthManager;
|
||||
import com.google.android.apps.mytracks.io.AuthManager.AuthCallback;
|
||||
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
|
||||
import com.google.android.common.gdata.AndroidXmlParserFactory;
|
||||
import com.google.wireless.gdata.client.GDataClient;
|
||||
@@ -126,11 +127,12 @@ class MyMapsGDataWrapper {
|
||||
}
|
||||
Log.d(MyMapsConstants.TAG, "GData error encountered: " + errorMessage);
|
||||
if (errorType == ERROR_AUTH && auth != null) {
|
||||
Runnable whenFinished = null;
|
||||
AuthCallback whenFinished = null;
|
||||
if (retryOnAuthFailure) {
|
||||
retriesPending++;
|
||||
whenFinished = new Runnable() {
|
||||
public void run() {
|
||||
whenFinished = new AuthCallback() {
|
||||
@Override
|
||||
public void onAuthResult(boolean success) {
|
||||
retriesPending--;
|
||||
retryOnAuthFailure = false;
|
||||
runQuery(query);
|
||||
|
||||
@@ -23,7 +23,7 @@ class MyMapsMapMetadata {
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = new String(title);
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
@@ -31,7 +31,7 @@ class MyMapsMapMetadata {
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = new String(description);
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public boolean getSearchable() {
|
||||
@@ -47,6 +47,6 @@ class MyMapsMapMetadata {
|
||||
}
|
||||
|
||||
public void setGDataEditUri(String editUri) {
|
||||
this.gdataEditUri = new String(editUri);
|
||||
this.gdataEditUri = editUri;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -85,8 +85,8 @@ class XmlMapsGDataParserFactory implements GDataParserFactory {
|
||||
|
||||
@Override
|
||||
public GDataSerializer createSerializer(Entry en) {
|
||||
if (en.getClass() == MapFeatureEntry.class) {
|
||||
return new XmlMapsGDataSerializer(xmlFactory, en);
|
||||
if (en instanceof MapFeatureEntry) {
|
||||
return new XmlMapsGDataSerializer(xmlFactory, (MapFeatureEntry) en);
|
||||
} else {
|
||||
return new XmlEntryGDataSerializer(xmlFactory, en);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
package com.google.android.apps.mytracks.io.mymaps;
|
||||
|
||||
import com.google.wireless.gdata.data.Entry;
|
||||
import com.google.wireless.gdata.data.StringUtils;
|
||||
import com.google.wireless.gdata.parser.ParseException;
|
||||
import com.google.wireless.gdata.parser.xml.XmlGDataParser;
|
||||
@@ -10,14 +9,14 @@ import com.google.wireless.gdata.serializer.xml.XmlEntryGDataSerializer;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
/**
|
||||
* Serializer of maps data for GData.
|
||||
*/
|
||||
@@ -29,11 +28,11 @@ class XmlMapsGDataSerializer extends XmlEntryGDataSerializer {
|
||||
private XmlParserFactory factory;
|
||||
private OutputStream stream;
|
||||
|
||||
public XmlMapsGDataSerializer(XmlParserFactory factory, Entry entry) {
|
||||
public XmlMapsGDataSerializer(XmlParserFactory factory, MapFeatureEntry entry) {
|
||||
super(factory, entry);
|
||||
|
||||
this.factory = factory;
|
||||
this.entry = (MapFeatureEntry) entry;
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-1
@@ -58,7 +58,8 @@ public class ResultDialogFactory {
|
||||
*/
|
||||
public static AlertDialog makeDialog(Activity activity, List<SendResult> results,
|
||||
DialogInterface.OnClickListener onOkClickListener,
|
||||
DialogInterface.OnClickListener onShareClickListener) {
|
||||
DialogInterface.OnClickListener onShareClickListener,
|
||||
DialogInterface.OnCancelListener onCancelListener) {
|
||||
boolean success = true;
|
||||
for (SendResult result : results) {
|
||||
if (!result.isSuccess()) {
|
||||
@@ -84,6 +85,8 @@ public class ResultDialogFactory {
|
||||
onShareClickListener);
|
||||
}
|
||||
|
||||
builder.setOnCancelListener(onCancelListener);
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,922 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.sendtogoogle;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.analytics.GoogleAnalyticsTracker;
|
||||
import com.google.android.apps.mytracks.AccountChooser;
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.MyMapsList;
|
||||
import com.google.android.apps.mytracks.ProgressIndicator;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.io.AuthManager;
|
||||
import com.google.android.apps.mytracks.io.AuthManager.AuthCallback;
|
||||
import com.google.android.apps.mytracks.io.AuthManagerFactory;
|
||||
import com.google.android.apps.mytracks.io.SendToDocs;
|
||||
import com.google.android.apps.mytracks.io.SendToFusionTables;
|
||||
import com.google.android.apps.mytracks.io.SendToFusionTables.OnSendCompletedListener;
|
||||
import com.google.android.apps.mytracks.io.SendToMyMaps;
|
||||
import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
|
||||
import com.google.android.apps.mytracks.io.mymaps.MyMapsConstants;
|
||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||
import com.google.android.apps.mytracks.util.UriUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnCancelListener;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helper activity for managing the sending of tracks to Google services.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class SendActivity extends Activity implements ProgressIndicator {
|
||||
// Keys for saved state variables.
|
||||
private static final String STATE_SEND_TO_MAPS = "mapsSend";
|
||||
private static final String STATE_SEND_TO_FUSION_TABLES = "fusionSend";
|
||||
private static final String STATE_SEND_TO_DOCS = "docsSend";
|
||||
private static final String STATE_DOCS_MESSAGE = "docsMsg";
|
||||
private static final String STATE_FUSION_TABLES_MESSAGE = "fusionMsg";
|
||||
private static final String STATE_MAPS_MESSAGE = "mapsMsg";
|
||||
private static final String STATE_DOCS_SUCCESS = "docsSuccess";
|
||||
private static final String STATE_FUSION_SUCCESS = "fusionSuccess";
|
||||
private static final String STATE_MAPS_SUCCESS = "mapsSuccess";
|
||||
private static final String STATE_STATE = "state";
|
||||
private static final String EXTRA_SHARE_LINK = "shareLink";
|
||||
private static final String STATE_ACCOUNT_TYPE = "accountType";
|
||||
private static final String STATE_ACCOUNT_NAME = "accountName";
|
||||
private static final String STATE_TABLE_ID = "tableId";
|
||||
private static final String STATE_MAP_ID = "mapId";
|
||||
|
||||
/** States for the state machine that defines the upload process. */
|
||||
private enum SendState {
|
||||
SEND_OPTIONS,
|
||||
START,
|
||||
AUTHENTICATE_MAPS,
|
||||
PICK_MAP,
|
||||
SEND_TO_MAPS,
|
||||
SEND_TO_MAPS_DONE,
|
||||
AUTHENTICATE_FUSION_TABLES,
|
||||
SEND_TO_FUSION_TABLES,
|
||||
SEND_TO_FUSION_TABLES_DONE,
|
||||
AUTHENTICATE_DOCS,
|
||||
AUTHENTICATE_TRIX,
|
||||
SEND_TO_DOCS,
|
||||
SEND_TO_DOCS_DONE,
|
||||
SHOW_RESULTS,
|
||||
SHARE_LINK,
|
||||
FINISH,
|
||||
DONE,
|
||||
NOT_READY
|
||||
}
|
||||
|
||||
private static final int SEND_DIALOG = 1;
|
||||
private static final int PROGRESS_DIALOG = 2;
|
||||
/* @VisibleForTesting */
|
||||
static final int DONE_DIALOG = 3;
|
||||
|
||||
// UI
|
||||
private ProgressDialog progressDialog;
|
||||
|
||||
// Services
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
private SharedPreferences sharedPreferences;
|
||||
private GoogleAnalyticsTracker tracker;
|
||||
|
||||
// Authentication
|
||||
private AuthManager lastAuth;
|
||||
private final HashMap<String, AuthManager> authMap = new HashMap<String, AuthManager>();
|
||||
private AccountChooser accountChooser;
|
||||
private String lastAccountName;
|
||||
private String lastAccountType;
|
||||
|
||||
// Send request information.
|
||||
private boolean shareRequested = false;
|
||||
private long sendTrackId;
|
||||
private boolean sendToMyMaps;
|
||||
private boolean sendToMyMapsNewMap;
|
||||
private boolean sendToFusionTables;
|
||||
private boolean sendToDocs;
|
||||
|
||||
// Send result information, used by results dialog.
|
||||
private boolean sendToMyMapsSuccess = false;
|
||||
private boolean sendToFusionTablesSuccess = false;
|
||||
private boolean sendToDocsSuccess = false;
|
||||
// TODO: Make these be used for showing results
|
||||
private String sendToMyMapsMessage;
|
||||
private String sendToFusionTablesMessage;
|
||||
private String sendToDocsMessage;
|
||||
|
||||
// Send result information, used to share a link.
|
||||
private String sendToMyMapsMapId;
|
||||
private String sendToFusionTablesTableId;
|
||||
|
||||
// Current sending state.
|
||||
private SendState currentState;
|
||||
|
||||
private final OnCancelListener finishOnCancelListener = new OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface arg0) {
|
||||
onAllDone();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Log.d(TAG, "SendActivity.onCreate");
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
||||
sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||
|
||||
tracker = GoogleAnalyticsTracker.getInstance();
|
||||
// Start the tracker in manual dispatch mode...
|
||||
tracker.start(getString(R.string.google_analytics_id),
|
||||
getApplicationContext());
|
||||
tracker.setProductVersion("android-mytracks",
|
||||
SystemUtils.getMyTracksVersion(this));
|
||||
|
||||
resetState();
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
restoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
// If we had the instance restored after it was done, reset it.
|
||||
if (currentState == SendState.DONE) {
|
||||
resetState();
|
||||
}
|
||||
|
||||
// Only consider the intent if we're not restoring from a previous state.
|
||||
if (currentState == SendState.SEND_OPTIONS) {
|
||||
if (!handleIntent()) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the state machine, at the start or restored state.
|
||||
Log.w(TAG, "Starting at state " + currentState);
|
||||
executeStateMachine(currentState);
|
||||
}
|
||||
|
||||
private boolean handleIntent() {
|
||||
Intent intent = getIntent();
|
||||
String action = intent.getAction();
|
||||
String type = intent.getType();
|
||||
Uri data = intent.getData();
|
||||
if (!Intent.ACTION_SEND.equals(action) ||
|
||||
!TracksColumns.CONTENT_ITEMTYPE.equals(type) ||
|
||||
!UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
|
||||
Log.e(TAG, "Got bad send intent: " + intent);
|
||||
return false;
|
||||
}
|
||||
|
||||
sendTrackId = ContentUris.parseId(data);
|
||||
shareRequested = intent.getBooleanExtra(EXTRA_SHARE_LINK, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
switch (id) {
|
||||
case SEND_DIALOG:
|
||||
return createSendDialog();
|
||||
case PROGRESS_DIALOG:
|
||||
return createProgressDialog();
|
||||
case DONE_DIALOG:
|
||||
return createDoneDialog();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Dialog createSendDialog() {
|
||||
final SendDialog sendDialog = new SendDialog(this);
|
||||
sendDialog.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which != DialogInterface.BUTTON_POSITIVE) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
dialog.dismiss();
|
||||
|
||||
sendToMyMaps = sendDialog.getSendToMyMaps();
|
||||
sendToMyMapsNewMap = sendDialog.getCreateNewMap();
|
||||
sendToFusionTables = sendDialog.getSendToFusionTables();
|
||||
sendToDocs = sendDialog.getSendToDocs();
|
||||
|
||||
executeStateMachine(SendState.START);
|
||||
}
|
||||
});
|
||||
sendDialog.setOnCancelListener(finishOnCancelListener);
|
||||
return sendDialog;
|
||||
}
|
||||
|
||||
private void restoreInstanceState(Bundle savedInstanceState) {
|
||||
currentState = SendState.values()[savedInstanceState.getInt(STATE_STATE)];
|
||||
|
||||
sendToMyMaps = savedInstanceState.getBoolean(STATE_SEND_TO_MAPS);
|
||||
sendToFusionTables = savedInstanceState.getBoolean(STATE_SEND_TO_FUSION_TABLES);
|
||||
sendToDocs = savedInstanceState.getBoolean(STATE_SEND_TO_DOCS);
|
||||
|
||||
sendToMyMapsSuccess = savedInstanceState.getBoolean(STATE_MAPS_SUCCESS);
|
||||
sendToFusionTablesSuccess = savedInstanceState.getBoolean(STATE_FUSION_SUCCESS);
|
||||
sendToDocsSuccess = savedInstanceState.getBoolean(STATE_DOCS_SUCCESS);
|
||||
|
||||
sendToMyMapsMessage = savedInstanceState.getString(STATE_MAPS_MESSAGE);
|
||||
sendToFusionTablesMessage = savedInstanceState.getString(STATE_FUSION_TABLES_MESSAGE);
|
||||
sendToDocsMessage = savedInstanceState.getString(STATE_DOCS_MESSAGE);
|
||||
|
||||
sendToMyMapsMapId = savedInstanceState.getString(STATE_MAP_ID);
|
||||
sendToFusionTablesTableId = savedInstanceState.getString(STATE_TABLE_ID);
|
||||
|
||||
lastAccountName = savedInstanceState.getString(STATE_ACCOUNT_NAME);
|
||||
lastAccountType = savedInstanceState.getString(STATE_ACCOUNT_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
outState.putInt(STATE_STATE, currentState.ordinal());
|
||||
|
||||
outState.putBoolean(STATE_MAPS_SUCCESS, sendToMyMapsSuccess);
|
||||
outState.putBoolean(STATE_FUSION_SUCCESS, sendToFusionTablesSuccess);
|
||||
outState.putBoolean(STATE_DOCS_SUCCESS, sendToDocsSuccess);
|
||||
|
||||
outState.putString(STATE_MAPS_MESSAGE, sendToMyMapsMessage);
|
||||
outState.putString(STATE_FUSION_TABLES_MESSAGE, sendToFusionTablesMessage);
|
||||
outState.putString(STATE_DOCS_MESSAGE, sendToDocsMessage);
|
||||
|
||||
outState.putString(STATE_MAP_ID, sendToMyMapsMapId);
|
||||
outState.putString(STATE_TABLE_ID, sendToFusionTablesTableId);
|
||||
|
||||
outState.putString(STATE_ACCOUNT_NAME, lastAccountName);
|
||||
outState.putString(STATE_ACCOUNT_TYPE, lastAccountType);
|
||||
|
||||
// TODO: Ideally we should serialize/restore the authenticator map and lastAuth somehow,
|
||||
// but it's highly unlikely we'll get killed while an auth dialog is displayed.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
Log.d(TAG, "SendActivity.onStop, state=" + currentState);
|
||||
tracker.dispatch();
|
||||
tracker.stop();
|
||||
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
Log.d(TAG, "SendActivity.onDestroy, state=" + currentState);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private void executeStateMachine(SendState startState) {
|
||||
currentState = startState;
|
||||
|
||||
// If a state handler returns NOT_READY, it means it's waiting for some
|
||||
// event, and will call this method again when it happens.
|
||||
while (currentState != SendState.DONE &&
|
||||
currentState != SendState.NOT_READY) {
|
||||
Log.d(TAG, "Executing state " + currentState);
|
||||
currentState = executeState(currentState);
|
||||
Log.d(TAG, "New state is " + currentState);
|
||||
}
|
||||
}
|
||||
|
||||
private SendState executeState(SendState state) {
|
||||
switch (state) {
|
||||
case SEND_OPTIONS:
|
||||
return showSendOptions();
|
||||
case START:
|
||||
return startSend();
|
||||
case AUTHENTICATE_MAPS:
|
||||
return authenticateToGoogleMaps();
|
||||
case PICK_MAP:
|
||||
return pickMap();
|
||||
case SEND_TO_MAPS:
|
||||
return sendToGoogleMaps();
|
||||
case SEND_TO_MAPS_DONE:
|
||||
return onSendToGoogleMapsDone();
|
||||
case AUTHENTICATE_FUSION_TABLES:
|
||||
return authenticateToFusionTables();
|
||||
case SEND_TO_FUSION_TABLES:
|
||||
return sendToFusionTables();
|
||||
case SEND_TO_FUSION_TABLES_DONE:
|
||||
return onSendToFusionTablesDone();
|
||||
case AUTHENTICATE_DOCS:
|
||||
return authenticateToGoogleDocs();
|
||||
case AUTHENTICATE_TRIX:
|
||||
return authenticateToGoogleTrix();
|
||||
case SEND_TO_DOCS:
|
||||
return sendToGoogleDocs();
|
||||
case SEND_TO_DOCS_DONE:
|
||||
return onSendToGoogleDocsDone();
|
||||
case SHOW_RESULTS:
|
||||
return onSendToGoogleDone();
|
||||
case SHARE_LINK:
|
||||
return shareLink();
|
||||
case FINISH:
|
||||
return onAllDone();
|
||||
default:
|
||||
Log.e(TAG, "Reached a non-executable state");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private SendState showSendOptions() {
|
||||
showDialog(SEND_DIALOG);
|
||||
|
||||
return SendState.NOT_READY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the process to send tracks to google.
|
||||
* This is called once the user has selected sending options via the
|
||||
* SendToGoogleDialog.
|
||||
*/
|
||||
private SendState startSend() {
|
||||
showDialog(PROGRESS_DIALOG);
|
||||
|
||||
if (sendToMyMaps) {
|
||||
return SendState.AUTHENTICATE_MAPS;
|
||||
} else if (sendToFusionTables) {
|
||||
return SendState.AUTHENTICATE_FUSION_TABLES;
|
||||
} else if (sendToDocs) {
|
||||
return SendState.AUTHENTICATE_DOCS;
|
||||
} else {
|
||||
Log.w(TAG, "Nowhere to upload to");
|
||||
return SendState.FINISH;
|
||||
}
|
||||
}
|
||||
|
||||
private Dialog createProgressDialog() {
|
||||
progressDialog = new ProgressDialog(this);
|
||||
progressDialog.setCancelable(false);
|
||||
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||
progressDialog.setTitle(R.string.progress_title);
|
||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
progressDialog.setMax(100);
|
||||
progressDialog.setProgress(0);
|
||||
|
||||
return progressDialog;
|
||||
}
|
||||
|
||||
private SendState authenticateToGoogleMaps() {
|
||||
Log.d(TAG, "SendActivity.authenticateToGoogleMaps");
|
||||
progressDialog.setProgress(0);
|
||||
progressDialog.setMessage(getString(
|
||||
R.string.progress_message_authenticating_mymaps));
|
||||
authenticate(Constants.AUTHENTICATE_TO_MY_MAPS, MyMapsConstants.SERVICE_NAME);
|
||||
// AUTHENTICATE_TO_MY_MAPS callback calls sendToGoogleMaps
|
||||
return SendState.NOT_READY;
|
||||
}
|
||||
|
||||
private SendState pickMap() {
|
||||
if (!sendToMyMapsNewMap) {
|
||||
// Ask the user to choose a map to upload into
|
||||
Intent listIntent = new Intent(this, MyMapsList.class);
|
||||
listIntent.putExtra(MyMapsList.EXTRA_ACCOUNT_NAME, lastAccountName);
|
||||
listIntent.putExtra(MyMapsList.EXTRA_ACCOUNT_TYPE, lastAccountType);
|
||||
startActivityForResult(listIntent, Constants.GET_MAP);
|
||||
// The callback for GET_MAP calls authenticateToGoogleMaps
|
||||
return SendState.NOT_READY;
|
||||
} else {
|
||||
return SendState.SEND_TO_MAPS;
|
||||
}
|
||||
}
|
||||
|
||||
private SendState sendToGoogleMaps() {
|
||||
tracker.trackPageView("/send/maps");
|
||||
|
||||
SendToMyMaps.OnSendCompletedListener onCompletion = new SendToMyMaps.OnSendCompletedListener() {
|
||||
@Override
|
||||
public void onSendCompleted(String mapId, boolean success, int statusMessage) {
|
||||
// TODO: Use this message
|
||||
sendToMyMapsMessage = getString(statusMessage);
|
||||
sendToMyMapsSuccess = success;
|
||||
if (sendToMyMapsSuccess) {
|
||||
sendToMyMapsMapId = mapId;
|
||||
// Update the map id for this track:
|
||||
try {
|
||||
Track track = providerUtils.getTrack(sendTrackId);
|
||||
if (track != null) {
|
||||
track.setMapId(mapId);
|
||||
providerUtils.updateTrack(track);
|
||||
} else {
|
||||
Log.w(TAG, "Updating map id failed.");
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
// If that fails whatever reasons we'll just log an error, but
|
||||
// continue.
|
||||
Log.w(TAG, "Updating map id failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
executeStateMachine(SendState.SEND_TO_MAPS_DONE);
|
||||
}
|
||||
};
|
||||
|
||||
if (sendToMyMapsMapId == null) {
|
||||
sendToMyMapsMapId = SendToMyMaps.NEW_MAP_ID;
|
||||
}
|
||||
|
||||
final SendToMyMaps sender = new SendToMyMaps(this, sendToMyMapsMapId, lastAuth,
|
||||
sendTrackId, this /*progressIndicator*/, onCompletion);
|
||||
|
||||
new Thread(sender, "SendToMyMaps").start();
|
||||
|
||||
return SendState.NOT_READY;
|
||||
}
|
||||
|
||||
private SendState onSendToGoogleMapsDone() {
|
||||
if (sendToFusionTables) {
|
||||
return SendState.AUTHENTICATE_FUSION_TABLES;
|
||||
} else if (sendToDocs) {
|
||||
return SendState.AUTHENTICATE_DOCS;
|
||||
} else {
|
||||
return SendState.SHOW_RESULTS;
|
||||
}
|
||||
}
|
||||
|
||||
private SendState authenticateToFusionTables() {
|
||||
progressDialog.setProgress(0);
|
||||
progressDialog.setMessage(getString(
|
||||
R.string.progress_message_authenticating_fusiontables));
|
||||
authenticate(Constants.AUTHENTICATE_TO_FUSION_TABLES, SendToFusionTables.SERVICE_ID);
|
||||
// AUTHENTICATE_TO_FUSION_TABLES callback calls sendToFusionTables
|
||||
return SendState.NOT_READY;
|
||||
}
|
||||
|
||||
private SendState sendToFusionTables() {
|
||||
tracker.trackPageView("/send/fusion_tables");
|
||||
|
||||
OnSendCompletedListener onCompletion = new OnSendCompletedListener() {
|
||||
@Override
|
||||
public void onSendCompleted(String tableId, boolean success,
|
||||
int statusMessage) {
|
||||
// TODO: Use this message
|
||||
sendToFusionTablesMessage = getString(statusMessage);
|
||||
sendToFusionTablesSuccess = success;
|
||||
if (sendToFusionTablesSuccess) {
|
||||
sendToFusionTablesTableId = tableId;
|
||||
// Update the table id for this track:
|
||||
try {
|
||||
Track track = providerUtils.getTrack(sendTrackId);
|
||||
if (track != null) {
|
||||
track.setTableId(tableId);
|
||||
providerUtils.updateTrack(track);
|
||||
} else {
|
||||
Log.w(TAG, "Updating table id failed.");
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
// If that fails whatever reasons we'll just log an error, but
|
||||
// continue.
|
||||
Log.w(TAG, "Updating table id failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
executeStateMachine(SendState.SEND_TO_FUSION_TABLES_DONE);
|
||||
}
|
||||
};
|
||||
|
||||
final SendToFusionTables sender = new SendToFusionTables(this, lastAuth,
|
||||
sendTrackId, this /*progressIndicator*/, onCompletion);
|
||||
|
||||
new Thread(sender, "SendToFusionTables").start();
|
||||
|
||||
return SendState.NOT_READY;
|
||||
}
|
||||
|
||||
private SendState onSendToFusionTablesDone() {
|
||||
if (sendToDocs) {
|
||||
return SendState.AUTHENTICATE_DOCS;
|
||||
} else {
|
||||
return SendState.SHOW_RESULTS;
|
||||
}
|
||||
}
|
||||
|
||||
private SendState authenticateToGoogleDocs() {
|
||||
setProgressValue(0);
|
||||
setProgressMessage(
|
||||
R.string.progress_message_authenticating_docs);
|
||||
authenticate(Constants.AUTHENTICATE_TO_DOCLIST, SendToDocs.GDATA_SERVICE_NAME_DOCLIST);
|
||||
// AUTHENTICATE_TO_DOCLIST callback calls authenticateToGoogleTrix
|
||||
return SendState.NOT_READY;
|
||||
}
|
||||
|
||||
private SendState authenticateToGoogleTrix() {
|
||||
setProgressValue(30);
|
||||
setProgressMessage(
|
||||
R.string.progress_message_authenticating_docs);
|
||||
authenticate(Constants.AUTHENTICATE_TO_TRIX, SendToDocs.GDATA_SERVICE_NAME_TRIX);
|
||||
// AUTHENTICATE_TO_TRIX callback calls sendToGoogleDocs
|
||||
return SendState.NOT_READY;
|
||||
}
|
||||
|
||||
private SendState sendToGoogleDocs() {
|
||||
Log.d(TAG, "Sending to Docs....");
|
||||
tracker.trackPageView("/send/docs");
|
||||
|
||||
setProgressValue(50);
|
||||
setProgressMessage(R.string.progress_message_sending_docs);
|
||||
final SendToDocs sender = new SendToDocs(this,
|
||||
authMap.get(SendToDocs.GDATA_SERVICE_NAME_TRIX),
|
||||
authMap.get(SendToDocs.GDATA_SERVICE_NAME_DOCLIST),
|
||||
this);
|
||||
Runnable onCompletion = new Runnable() {
|
||||
public void run() {
|
||||
setProgressValue(100);
|
||||
|
||||
// TODO: Use this message
|
||||
sendToDocsMessage = sender.getStatusMessage();
|
||||
sendToDocsSuccess = sender.wasSuccess();
|
||||
|
||||
executeStateMachine(SendState.SEND_TO_DOCS_DONE);
|
||||
}
|
||||
};
|
||||
sender.setOnCompletion(onCompletion);
|
||||
sender.sendToDocs(sendTrackId);
|
||||
|
||||
return SendState.NOT_READY;
|
||||
}
|
||||
|
||||
private SendState onSendToGoogleDocsDone() {
|
||||
return SendState.SHOW_RESULTS;
|
||||
}
|
||||
|
||||
private SendState onSendToGoogleDone() {
|
||||
tracker.dispatch();
|
||||
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "Sending to Google done.");
|
||||
dismissDialog(PROGRESS_DIALOG);
|
||||
dismissDialog(SEND_DIALOG);
|
||||
|
||||
// Ensure a new done dialog is created each time.
|
||||
// This is required because the send results must be available at the
|
||||
// time the dialog is created.
|
||||
removeDialog(DONE_DIALOG);
|
||||
showDialog(DONE_DIALOG);
|
||||
}
|
||||
});
|
||||
|
||||
return SendState.NOT_READY;
|
||||
}
|
||||
|
||||
private Dialog createDoneDialog() {
|
||||
Log.d(TAG, "Creating done dialog");
|
||||
// We've finished sending the track to the user-selected services. Now
|
||||
// we tell them the results of the upload, and optionally share the track.
|
||||
// There are a few different paths through this code:
|
||||
//
|
||||
// 1. The user pre-requested a share (shareRequested == true). We're going
|
||||
// to display the result dialog *without* the share button (the share
|
||||
// listener will be null). The OK button listener will initiate the
|
||||
// share.
|
||||
//
|
||||
// 2. The user did not pre-request a share, and the set of services to
|
||||
// which we succeeded in uploading the track are compatible with
|
||||
// sharing. We'll display a share button (the share listener will be
|
||||
// non-null), and will share the link if the user clicks it.
|
||||
//
|
||||
// 3. The user did not pre-request a share, and the set of services to
|
||||
// which we succeeded in uploading the track are incompatible with
|
||||
// sharing. We won't display a share button.
|
||||
|
||||
List<SendResult> results = makeSendToGoogleResults();
|
||||
final boolean canShare = sendToFusionTablesTableId != null || sendToMyMapsMapId != null;
|
||||
|
||||
final OnClickListener finishListener = new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
executeStateMachine(SendState.FINISH);
|
||||
}
|
||||
};
|
||||
|
||||
DialogInterface.OnClickListener doShareListener = null;
|
||||
if (canShare) {
|
||||
doShareListener = new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
|
||||
executeStateMachine(SendState.SHARE_LINK);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
DialogInterface.OnClickListener onOkListener = (canShare && shareRequested)
|
||||
? doShareListener : finishListener;
|
||||
DialogInterface.OnClickListener onShareListener = (canShare && !shareRequested)
|
||||
? doShareListener : null;
|
||||
|
||||
return ResultDialogFactory.makeDialog(this, results, onOkListener, onShareListener, finishOnCancelListener);
|
||||
}
|
||||
|
||||
private SendState onAllDone() {
|
||||
Log.d(TAG, "All sending done.");
|
||||
removeDialog(PROGRESS_DIALOG);
|
||||
removeDialog(SEND_DIALOG);
|
||||
removeDialog(DONE_DIALOG);
|
||||
progressDialog = null;
|
||||
finish();
|
||||
return SendState.DONE;
|
||||
}
|
||||
|
||||
private SendState shareLink() {
|
||||
String url = null;
|
||||
if (sendToMyMaps && sendToMyMapsSuccess) {
|
||||
// Prefer a link to My Maps
|
||||
url = MapsFacade.buildMapUrl(sendToMyMapsMapId);
|
||||
} else if (sendToFusionTables && sendToFusionTablesSuccess) {
|
||||
// Otherwise try using the link to fusion tables
|
||||
url = getFusionTablesUrl(sendTrackId);
|
||||
}
|
||||
|
||||
if (url != null) {
|
||||
shareLinkToMap(url);
|
||||
} else {
|
||||
Log.w(TAG, "Failed to share link");
|
||||
}
|
||||
|
||||
return SendState.FINISH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shares a link to a My Map or Fusion Table via external app (email, gmail, ...)
|
||||
* A chooser with apps that support text/plain will be shown to the user.
|
||||
*/
|
||||
private void shareLinkToMap(String url) {
|
||||
boolean shareUrlOnly = sharedPreferences.getBoolean(
|
||||
getString(R.string.share_url_only_key), false);
|
||||
String msg = shareUrlOnly ? url : String.format(
|
||||
getResources().getText(R.string.share_map_body_format).toString(), url);
|
||||
|
||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||
shareIntent.setType("text/plain");
|
||||
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
|
||||
getResources().getText(R.string.share_map_subject).toString());
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT, msg);
|
||||
startActivity(Intent.createChooser(shareIntent,
|
||||
getResources().getText(R.string.share_map).toString()));
|
||||
}
|
||||
|
||||
protected String getFusionTablesUrl(long trackId) {
|
||||
Track track = providerUtils.getTrack(trackId);
|
||||
return SendToFusionTables.getMapVisualizationUrl(track);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of {@link SendResult} instances based on the set of
|
||||
* services selected in {@link SendDialog} and the results as known to
|
||||
* this class.
|
||||
*/
|
||||
private List<SendResult> makeSendToGoogleResults() {
|
||||
List<SendResult> results = new ArrayList<SendResult>();
|
||||
if (sendToMyMaps) {
|
||||
results.add(new SendResult(SendType.MYMAPS, sendToMyMapsSuccess));
|
||||
}
|
||||
if (sendToFusionTables) {
|
||||
results.add(new SendResult(SendType.FUSION_TABLES,
|
||||
sendToFusionTablesSuccess));
|
||||
}
|
||||
if (sendToDocs) {
|
||||
results.add(new SendResult(SendType.DOCS, sendToDocsSuccess));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the authentication manager which obtains an authentication
|
||||
* token, prompting the user for a login and password if needed.
|
||||
*/
|
||||
private void authenticate(final int requestCode, final String service) {
|
||||
lastAuth = authMap.get(service);
|
||||
if (lastAuth == null) {
|
||||
Log.i(TAG, "Creating a new authentication for service: " + service);
|
||||
lastAuth = AuthManagerFactory.getAuthManager(this,
|
||||
Constants.GET_LOGIN,
|
||||
null,
|
||||
true,
|
||||
service);
|
||||
authMap.put(service, lastAuth);
|
||||
}
|
||||
|
||||
Log.d(TAG, "Logging in to " + service + "...");
|
||||
if (AuthManagerFactory.useModernAuthManager()) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
chooseAccount(requestCode, service);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
doLogin(requestCode, service, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void chooseAccount(final int requestCode, final String service) {
|
||||
if (accountChooser == null) {
|
||||
accountChooser = new AccountChooser();
|
||||
|
||||
// Restore state if necessary.
|
||||
if (lastAccountName != null && lastAccountType != null) {
|
||||
accountChooser.setChosenAccount(lastAccountName, lastAccountType);
|
||||
}
|
||||
}
|
||||
|
||||
accountChooser.chooseAccount(SendActivity.this,
|
||||
new AccountChooser.AccountHandler() {
|
||||
@Override
|
||||
public void onAccountSelected(Account account) {
|
||||
if (account == null) {
|
||||
dismissDialog(PROGRESS_DIALOG);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
lastAccountName = account.name;
|
||||
lastAccountType = account.type;
|
||||
doLogin(requestCode, service, account);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void doLogin(final int requestCode, final String service, final Object account) {
|
||||
lastAuth.doLogin(new AuthCallback() {
|
||||
@Override
|
||||
public void onAuthResult(boolean success) {
|
||||
Log.i(TAG, "Login success for " + service + ": " + success);
|
||||
if (!success) {
|
||||
executeStateMachine(SendState.SHOW_RESULTS);
|
||||
return;
|
||||
}
|
||||
|
||||
onLoginSuccess(requestCode);
|
||||
}
|
||||
}, account);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode,
|
||||
final Intent results) {
|
||||
SendState nextState = null;
|
||||
switch (requestCode) {
|
||||
case Constants.GET_LOGIN: {
|
||||
if (resultCode == RESULT_CANCELED || lastAuth == null) {
|
||||
nextState = SendState.FINISH;
|
||||
break;
|
||||
}
|
||||
|
||||
// This will invoke onAuthResult appropriately.
|
||||
lastAuth.authResult(resultCode, results);
|
||||
break;
|
||||
}
|
||||
case Constants.GET_MAP: {
|
||||
// User picked a map to upload to
|
||||
Log.d(TAG, "Get map result: " + resultCode);
|
||||
if (resultCode == RESULT_OK) {
|
||||
if (results.hasExtra("mapid")) {
|
||||
sendToMyMapsMapId = results.getStringExtra("mapid");
|
||||
}
|
||||
nextState = SendState.SEND_TO_MAPS;
|
||||
} else {
|
||||
nextState = SendState.FINISH;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
Log.e(TAG, "Unrequested result: " + requestCode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextState != null) {
|
||||
executeStateMachine(nextState);
|
||||
}
|
||||
}
|
||||
|
||||
private void onLoginSuccess(int requestCode) {
|
||||
SendState nextState;
|
||||
switch (requestCode) {
|
||||
case Constants.AUTHENTICATE_TO_MY_MAPS:
|
||||
// Authenticated with Google My Maps
|
||||
nextState = SendState.PICK_MAP;
|
||||
break;
|
||||
case Constants.AUTHENTICATE_TO_FUSION_TABLES:
|
||||
// Authenticated with Google Fusion Tables
|
||||
nextState = SendState.SEND_TO_FUSION_TABLES;
|
||||
break;
|
||||
case Constants.AUTHENTICATE_TO_DOCLIST:
|
||||
// Authenticated with Google Docs
|
||||
nextState = SendState.AUTHENTICATE_TRIX;
|
||||
break;
|
||||
case Constants.AUTHENTICATE_TO_TRIX:
|
||||
// Authenticated with Trix
|
||||
nextState = SendState.SEND_TO_DOCS;
|
||||
break;
|
||||
|
||||
default: {
|
||||
Log.e(TAG, "Unrequested login code: " + requestCode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
executeStateMachine(nextState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets status information for sending to MyMaps/Docs.
|
||||
*/
|
||||
private void resetState() {
|
||||
currentState = SendState.SEND_OPTIONS;
|
||||
sendToMyMapsMapId = null;
|
||||
sendToMyMapsMessage = "";
|
||||
sendToMyMapsSuccess = true;
|
||||
sendToFusionTablesMessage = "";
|
||||
sendToFusionTablesSuccess = true;
|
||||
sendToDocsMessage = "";
|
||||
sendToDocsSuccess = true;
|
||||
sendToFusionTablesTableId = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressMessage(final int resId) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.setMessage(getString(resId));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressValue(final int percent) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.setProgress(percent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearProgressMessage() {
|
||||
progressDialog.setMessage("");
|
||||
}
|
||||
|
||||
public static void sendToGoogle(Context ctx, long trackId, boolean shareLink) {
|
||||
Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
|
||||
|
||||
Intent intent = new Intent(ctx, SendActivity.class);
|
||||
intent.setAction(Intent.ACTION_SEND);
|
||||
intent.setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
|
||||
intent.putExtra(SendActivity.EXTRA_SHARE_LINK, shareLink);
|
||||
ctx.startActivity(intent);
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,6 @@
|
||||
package com.google.android.apps.mytracks.io.sendtogoogle;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.DialogManager;
|
||||
import com.google.android.apps.mytracks.MyTracks;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Dialog;
|
||||
@@ -42,15 +40,13 @@ import android.widget.RadioGroup;
|
||||
*/
|
||||
public class SendDialog extends Dialog {
|
||||
|
||||
private RadioGroup groupMyMaps;
|
||||
private RadioButton createNewMapRadioButton;
|
||||
private RadioButton pickMapRadioButton;
|
||||
private CheckBox sendToMyMapsCheckBox;
|
||||
private CheckBox sendToFusionTablesCheckBox;
|
||||
private CheckBox sendToDocsCheckBox;
|
||||
private RadioButton sendStatsRadioButton;
|
||||
private RadioButton sendStatsAndPointsRadioButton;
|
||||
private Button sendButton;
|
||||
private OnClickListener clickListener;
|
||||
|
||||
public SendDialog(Context context) {
|
||||
super(context);
|
||||
@@ -62,18 +58,38 @@ public class SendDialog extends Dialog {
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.mytracks_send_to_google);
|
||||
|
||||
final Button sendButton = (Button) findViewById(R.id.sendtogoogle_send_now);
|
||||
final RadioGroup groupMyMaps = (RadioGroup) findViewById(R.id.sendtogoogle_group_mymaps);
|
||||
sendToMyMapsCheckBox =
|
||||
(CheckBox) findViewById(R.id.sendtogoogle_google_mymaps);
|
||||
sendToFusionTablesCheckBox =
|
||||
(CheckBox) findViewById(R.id.sendtogoogle_google_fusiontables);
|
||||
sendToDocsCheckBox = (CheckBox) findViewById(R.id.sendtogoogle_google_docs);
|
||||
createNewMapRadioButton =
|
||||
(RadioButton) findViewById(R.id.sendtogoogle_create_new_map);
|
||||
pickMapRadioButton =
|
||||
(RadioButton) findViewById(R.id.sendtogoogle_pick_existing_map);
|
||||
RadioButton sendStatsRadioButton = (RadioButton) findViewById(R.id.sendtogoogle_send_stats);
|
||||
sendStatsAndPointsRadioButton = (RadioButton) findViewById(
|
||||
R.id.sendtogoogle_send_stats_and_points);
|
||||
|
||||
Button cancel = (Button) findViewById(R.id.sendtogoogle_cancel);
|
||||
cancel.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
MyTracks.getInstance().dismissDialog(DialogManager.DIALOG_SEND_TO_GOOGLE);
|
||||
if (clickListener != null) {
|
||||
clickListener.onClick(SendDialog.this, BUTTON_NEGATIVE);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
Button send = (Button) findViewById(R.id.sendtogoogle_send_now);
|
||||
send.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
if (clickListener != null) {
|
||||
clickListener.onClick(SendDialog.this, BUTTON_POSITIVE);
|
||||
}
|
||||
dismiss();
|
||||
MyTracks.getInstance().sendToGoogle();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -86,25 +102,9 @@ public class SendDialog extends Dialog {
|
||||
groupMyMaps.setVisibility(sendToMyMapsCheckBox.isChecked() ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
};
|
||||
|
||||
sendButton = (Button) findViewById(R.id.sendtogoogle_send_now);
|
||||
groupMyMaps = (RadioGroup) findViewById(R.id.sendtogoogle_group_mymaps);
|
||||
sendToMyMapsCheckBox =
|
||||
(CheckBox) findViewById(R.id.sendtogoogle_google_mymaps);
|
||||
sendToMyMapsCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
||||
sendToFusionTablesCheckBox =
|
||||
(CheckBox) findViewById(R.id.sendtogoogle_google_fusiontables);
|
||||
sendToFusionTablesCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
||||
sendToDocsCheckBox = (CheckBox) findViewById(R.id.sendtogoogle_google_docs);
|
||||
sendToDocsCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
||||
createNewMapRadioButton =
|
||||
(RadioButton) findViewById(R.id.sendtogoogle_create_new_map);
|
||||
pickMapRadioButton =
|
||||
(RadioButton) findViewById(R.id.sendtogoogle_pick_existing_map);
|
||||
sendStatsRadioButton =
|
||||
(RadioButton) findViewById(R.id.sendtogoogle_send_stats);
|
||||
sendStatsAndPointsRadioButton = (RadioButton) findViewById(
|
||||
R.id.sendtogoogle_send_stats_and_points);
|
||||
|
||||
SharedPreferences prefs =
|
||||
getContext().getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||
@@ -163,6 +163,10 @@ public class SendDialog extends Dialog {
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
public void setOnClickListener(OnClickListener clickListener) {
|
||||
this.clickListener = clickListener;
|
||||
}
|
||||
|
||||
public boolean getSendToMyMaps() {
|
||||
return sendToMyMapsCheckBox.isChecked();
|
||||
}
|
||||
@@ -182,4 +186,4 @@ public class SendDialog extends Dialog {
|
||||
public boolean getSendStatsAndPoints() {
|
||||
return sendStatsAndPointsRadioButton.isChecked();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
@@ -24,7 +24,7 @@ import android.util.Log;
|
||||
|
||||
/**
|
||||
* A class that manages reading the shared preferences for the service.
|
||||
*
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
||||
@@ -39,6 +39,7 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
||||
private final String minRecordingIntervalKey;
|
||||
private final String minRequiredAccuracyKey;
|
||||
private final String recordingTrackKey;
|
||||
private final String selectedTrackKey;
|
||||
private final String splitFrequencyKey;
|
||||
|
||||
public PreferenceManager(TrackRecordingService service) {
|
||||
@@ -51,14 +52,14 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
||||
throw new IllegalStateException("Couldn't get shared preferences");
|
||||
}
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
|
||||
announcementFrequencyKey =
|
||||
service.getString(R.string.announcement_frequency_key);
|
||||
autoResumeTrackCurrentRetryKey =
|
||||
service.getString(R.string.auto_resume_track_current_retry_key);
|
||||
autoResumeTrackTimeoutKey =
|
||||
service.getString(R.string.auto_resume_track_timeout_key);
|
||||
maxRecordingDistanceKey =
|
||||
maxRecordingDistanceKey =
|
||||
service.getString(R.string.max_recording_distance_key);
|
||||
metricUnitsKey =
|
||||
service.getString(R.string.metric_units_key);
|
||||
@@ -70,9 +71,11 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
||||
service.getString(R.string.min_required_accuracy_key);
|
||||
recordingTrackKey =
|
||||
service.getString(R.string.recording_track_key);
|
||||
selectedTrackKey =
|
||||
service.getString(R.string.selected_track_key);
|
||||
splitFrequencyKey =
|
||||
service.getString(R.string.split_frequency_key);
|
||||
|
||||
|
||||
// Refresh all properties.
|
||||
onSharedPreferenceChanged(sharedPreferences, null);
|
||||
}
|
||||
@@ -84,7 +87,7 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
||||
* @param key the key that changed (may be null to update all preferences)
|
||||
*/
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
||||
public void onSharedPreferenceChanged(SharedPreferences preferences,
|
||||
String key) {
|
||||
if (service == null) {
|
||||
Log.w(Constants.TAG,
|
||||
@@ -93,13 +96,13 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
||||
return;
|
||||
}
|
||||
if (key == null || key.equals(minRecordingDistanceKey)) {
|
||||
service.setMinRecordingDistance(
|
||||
sharedPreferences.getInt(
|
||||
minRecordingDistanceKey,
|
||||
Constants.DEFAULT_MIN_RECORDING_DISTANCE));
|
||||
int minRecordingDistance = sharedPreferences.getInt(
|
||||
minRecordingDistanceKey,
|
||||
Constants.DEFAULT_MIN_RECORDING_DISTANCE);
|
||||
service.setMinRecordingDistance(minRecordingDistance);
|
||||
Log.d(Constants.TAG,
|
||||
"TrackRecordingService: minRecordingDistance = "
|
||||
+ service.getMinRecordingDistance());
|
||||
+ minRecordingDistance);
|
||||
}
|
||||
if (key == null || key.equals(maxRecordingDistanceKey)) {
|
||||
service.setMaxRecordingDistance(sharedPreferences.getInt(
|
||||
@@ -149,7 +152,7 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
||||
if (key == null || key.equals(recordingTrackKey)) {
|
||||
long recordingTrackId = sharedPreferences.getLong(recordingTrackKey, -1);
|
||||
// Only read the id if it is valid.
|
||||
// Setting it to -1 should only happen in
|
||||
// Setting it to -1 should only happen in
|
||||
// TrackRecordingService.endCurrentTrack()
|
||||
if (recordingTrackId > 0) {
|
||||
service.setRecordingTrackId(recordingTrackId);
|
||||
@@ -164,7 +167,7 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
||||
sharedPreferences.getBoolean(metricUnitsKey, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setAutoResumeTrackCurrentRetry(int retryAttempts) {
|
||||
sharedPreferences
|
||||
.edit()
|
||||
@@ -178,7 +181,14 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
||||
.putLong(recordingTrackKey, id)
|
||||
.commit();
|
||||
}
|
||||
|
||||
|
||||
public void setSelectedTrack(long id) {
|
||||
sharedPreferences
|
||||
.edit()
|
||||
.putLong(selectedTrackKey, id)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
|
||||
service = null;
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningServiceInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helper for reading service state.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class ServiceUtils {
|
||||
|
||||
/**
|
||||
* Checks whether we're currently recording.
|
||||
* The checking is done by calling the service, if provided, or alternatively by reading
|
||||
* recording state saved to preferences.
|
||||
*
|
||||
* @param ctx the current context
|
||||
* @param service the service, or null if not bound to it
|
||||
* @param preferences the preferences, or null if not available
|
||||
* @return true if the service is recording (or supposed to be recording), false otherwise
|
||||
*/
|
||||
public static boolean isRecording(Context ctx, ITrackRecordingService service, SharedPreferences preferences) {
|
||||
if (service != null) {
|
||||
try {
|
||||
return service.isRecording();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to check if service is recording", e);
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "Failed to check if service is recording", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (preferences == null) {
|
||||
preferences = ctx.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||
}
|
||||
return preferences.getLong(ctx.getString(R.string.recording_track_key), -1) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the recording service is currently running.
|
||||
*
|
||||
* @param ctx the current context
|
||||
* @return true if the service is running, false otherwise
|
||||
*/
|
||||
public static boolean isServiceRunning(Context ctx) {
|
||||
ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
|
||||
|
||||
for (RunningServiceInfo serviceInfo : services) {
|
||||
ComponentName componentName = serviceInfo.service;
|
||||
String serviceName = componentName.getClassName();
|
||||
if (serviceName.equals(TrackRecordingService.class.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private ServiceUtils() {}
|
||||
}
|
||||
+765
-759
File diff suppressed because it is too large
Load Diff
+170
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.IBinder;
|
||||
import android.os.IBinder.DeathRecipient;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Wrapper for the connection to the track recording service.
|
||||
* This handles connection/disconnection internally, only returning a real
|
||||
* service for use if one is available and connected.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class TrackRecordingServiceConnection {
|
||||
private ITrackRecordingService boundService;
|
||||
|
||||
private final DeathRecipient deathRecipient = new DeathRecipient() {
|
||||
@Override
|
||||
public void binderDied() {
|
||||
Log.d(TAG, "Service died");
|
||||
setBoundService(null);
|
||||
}
|
||||
};
|
||||
|
||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
Log.i(TAG, "Connected to service");
|
||||
try {
|
||||
service.linkToDeath(deathRecipient, 0);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to bind a death recipient", e);
|
||||
}
|
||||
|
||||
setBoundService(ITrackRecordingService.Stub.asInterface(service));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
Log.i(TAG, "Disconnected from service");
|
||||
setBoundService(null);
|
||||
}
|
||||
};
|
||||
|
||||
private final Context context;
|
||||
|
||||
private final Runnable bindChangedCallback;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param context the current context
|
||||
* @param bindChangedCallback a callback to be executed when the state of the
|
||||
* service binding changes
|
||||
*/
|
||||
public TrackRecordingServiceConnection(Context context, Runnable bindChangedCallback) {
|
||||
this.context = context;
|
||||
this.bindChangedCallback = bindChangedCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds to the service, starting it if necessary.
|
||||
*/
|
||||
public void startAndBind() {
|
||||
bindService(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds to the service, only if it's already running.
|
||||
*/
|
||||
public void bindIfRunning() {
|
||||
bindService(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbinds from and stops the service.
|
||||
*/
|
||||
public void stop() {
|
||||
unbind();
|
||||
|
||||
Log.d(TAG, "Stopping service");
|
||||
Intent intent = new Intent(context, TrackRecordingService.class);
|
||||
context.stopService(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbinds from the service (but leaves it running).
|
||||
*/
|
||||
public void unbind() {
|
||||
Log.d(TAG, "Unbinding from the service");
|
||||
try {
|
||||
context.unbindService(serviceConnection);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Means we weren't bound, which is ok.
|
||||
}
|
||||
|
||||
setBoundService(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the service if connected to it, or null if not connected.
|
||||
*/
|
||||
public ITrackRecordingService getServiceIfBound() {
|
||||
checkBindingAlive();
|
||||
|
||||
return boundService;
|
||||
}
|
||||
|
||||
private void checkBindingAlive() {
|
||||
if (boundService != null &&
|
||||
!boundService.asBinder().isBinderAlive()) {
|
||||
setBoundService(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void bindService(boolean startIfNeeded) {
|
||||
if (boundService != null) {
|
||||
// Already bound.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!startIfNeeded && !ServiceUtils.isServiceRunning(context)) {
|
||||
// Not running, start not requested.
|
||||
Log.d(TAG, "Service not running, not binding to it.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (startIfNeeded) {
|
||||
Log.i(TAG, "Starting the service");
|
||||
Intent intent = new Intent(context, TrackRecordingService.class);
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
Log.i(TAG, "Binding to the service");
|
||||
Intent intent = new Intent(context, TrackRecordingService.class);
|
||||
int flags = SystemUtils.isRelease(context) ? 0 : Context.BIND_DEBUG_UNBIND;
|
||||
context.bindService(intent, serviceConnection, flags);
|
||||
}
|
||||
|
||||
private void setBoundService(ITrackRecordingService service) {
|
||||
boundService = service;
|
||||
if (bindChangedCallback != null) {
|
||||
bindChangedCallback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -394,8 +394,9 @@ public class BluetoothConnectionManager {
|
||||
|
||||
offset = 0;
|
||||
|
||||
// Send the obtained bytes to the UI Activity
|
||||
handler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
|
||||
// Send copy of the obtained bytes to the UI Activity.
|
||||
// Avoids memory inconsistency issues.
|
||||
handler.obtainMessage(MESSAGE_READ, bytes, -1, buffer.clone())
|
||||
.sendToTarget();
|
||||
} catch (IOException e) {
|
||||
Log.e(Constants.TAG, "disconnected", e);
|
||||
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
|
||||
/**
|
||||
* An implementation of a Sensor MessageParser for Polar Wearlink Bluetooth HRM.
|
||||
*
|
||||
* Polar Bluetooth Wearlink packet example;
|
||||
* Hdr Len Chk Seq Status HeartRate RRInterval_16-bits
|
||||
* FE 08 F7 06 F1 48 03 64
|
||||
* where;
|
||||
* Hdr always = 254 (0xFE),
|
||||
* Chk = 255 - Len
|
||||
* Seq range 0 to 15
|
||||
* Status = Upper nibble may be battery voltage
|
||||
* bit 0 is Beat Detection flag.
|
||||
*
|
||||
* Additional packet examples;
|
||||
* FE 08 F7 06 F1 48 03 64
|
||||
* FE 0A F5 06 F1 48 03 64 03 70
|
||||
*
|
||||
* @author John R. Gerthoffer
|
||||
*/
|
||||
public class PolarMessageParser implements MessageParser {
|
||||
|
||||
private int lastHeartRate = 0;
|
||||
|
||||
/**
|
||||
* Applies Polar packet validation rules to buffer.
|
||||
* Polar packets are checked for following;
|
||||
* offset 0 = header byte, 254 (0xFE).
|
||||
* offset 1 = packet length byte, 8, 10, 12, 14.
|
||||
* offset 2 = check byte, 255 - packet length.
|
||||
* offset 3 = sequence byte, range from 0 to 15.
|
||||
*
|
||||
* @param an array of bytes to parse
|
||||
* @param buffer offset to beginning of packet.
|
||||
* @return whether buffer has a valid packet at offset i
|
||||
*/
|
||||
private boolean packetValid (byte[] buffer, int i) {
|
||||
boolean headerValid = (buffer[i] & 0xFF) == 0xFE;
|
||||
boolean checkbyteValid = (buffer[i + 2] & 0xFF) == (0xFF - (buffer[i + 1] & 0xFF));
|
||||
boolean sequenceValid = (buffer[i + 3] & 0xFF) < 16;
|
||||
|
||||
return headerValid && checkbyteValid && sequenceValid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sensor.SensorDataSet parseBuffer(byte[] buffer) {
|
||||
|
||||
int heartRate = 0;
|
||||
boolean heartrateValid = false;
|
||||
|
||||
// Minimum length Polar packets is 8, so stop search 8 bytes before buffer ends.
|
||||
for (int i = 0; i < buffer.length - 8; i++) {
|
||||
heartrateValid = packetValid(buffer,i);
|
||||
if (heartrateValid) {
|
||||
heartRate = buffer[i + 5] & 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If our buffer is corrupted, use decaying last good value.
|
||||
if(!heartrateValid) {
|
||||
heartRate = (int) (lastHeartRate * 0.8);
|
||||
if(heartRate < 50)
|
||||
heartRate = 0;
|
||||
}
|
||||
|
||||
lastHeartRate = heartRate; // Remember good value for next time.
|
||||
|
||||
// Heart Rate
|
||||
Sensor.SensorData.Builder b = Sensor.SensorData.newBuilder()
|
||||
.setValue(heartRate)
|
||||
.setState(Sensor.SensorState.SENDING);
|
||||
|
||||
Sensor.SensorDataSet sds = Sensor.SensorDataSet.newBuilder()
|
||||
.setCreationTime(System.currentTimeMillis())
|
||||
.setHeartRate(b)
|
||||
.build();
|
||||
|
||||
return sds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies packet validation rules to buffer
|
||||
*
|
||||
* @param an array of bytes to parse
|
||||
* @return whether buffer has a valid packet starting at index zero
|
||||
*/
|
||||
@Override
|
||||
public boolean isValid(byte[] buffer) {
|
||||
return packetValid(buffer,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Polar uses variable packet sizes; 8, 10, 12, 14 and rarely 16.
|
||||
* The most frequent are 8 and 10.
|
||||
* We will wait for 16 bytes.
|
||||
* This way, we are assured of getting one good one.
|
||||
*
|
||||
* @return the size of buffer needed to parse a good packet
|
||||
*/
|
||||
@Override
|
||||
public int getFrameSize() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches buffer for the beginning of a valid packet.
|
||||
*
|
||||
* @param an array of bytes to parse
|
||||
* @return index to beginning of good packet, or -1 if none found.
|
||||
*/
|
||||
@Override
|
||||
public int findNextAlignment(byte[] buffer) {
|
||||
// Minimum length Polar packets is 8, so stop search 8 bytes before buffer ends.
|
||||
for (int i = 0; i < buffer.length - 8; i++) {
|
||||
if (packetValid(buffer,i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* PolarSensorManager - A sensor manager for Polar heart rate monitors.
|
||||
*/
|
||||
|
||||
public class PolarSensorManager extends BluetoothSensorManager {
|
||||
public PolarSensorManager(Context context) {
|
||||
super(context, new PolarMessageParser());
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user