Compare commits

..

461 Commits

Author SHA1 Message Date
Matthew Simmons 5a1c52d3b5 Code review fix 2011-02-08 17:32:19 -05:00
Matthew Simmons 02c374b61e Map Fusion Tables uploading failures to the HTTP Exception that GData expects.
Fix typo in proguard disabling comment.
2011-02-08 17:23:39 -05:00
Matthew Simmons f2094e049a Disable proguard 2011-02-08 17:10:59 -05:00
Sandor Dornbush 8ff2b3b090 Merge chart changes. 2011-02-08 07:28:23 -08:00
Sandor Dornbush eeaa363132 Minor chart fixes. 2011-02-07 21:50:12 -08:00
Sandor Dornbush 43e51848fc Don't trap runtime exceptions. 2011-02-07 17:03:06 -08:00
Sandor Dornbush 8b17117220 Unify chart display code. 2011-02-06 19:37:43 -08:00
Sandor Dornbush a4e06a4ce0 Merge Matthew's changes. 2011-02-04 15:35:16 -08:00
Sandor Dornbush 4d55f5ebdb Merge Matthew's changes. 2011-02-04 15:34:22 -08:00
Sandor Dornbush 268f3c77c2 Merge FR translations. 2011-02-04 15:32:28 -08:00
Sandor Dornbush ce73718620 Fine tune JA translation. 2011-02-04 15:28:23 -08:00
Sandor Dornbush d307c58f87 Fine tune JA translation. 2011-02-04 15:23:20 -08:00
Sandor Dornbush e7ec021da8 Address comments. 2011-02-04 15:13:33 -08:00
Matthew Simmons ca94fc7a96 Reuse existing messages 2011-02-04 17:15:34 -05:00
Matthew Simmons 9d650c4885 Rearrange Fusion Tables upload progress reporting 2011-02-04 16:21:20 -05:00
Sandor Dornbush c6d9be499c Merge heads. 2011-02-04 12:16:36 -08:00
Matthew Simmons 0e78e8b3f9 Remove unused imports 2011-02-04 15:09:03 -05:00
Matthew Simmons 2a99278b52 SQL-escape the track name
Don't catch HTTPException in runUpdate/query -- let GDataWrapper do that for us
2011-02-04 15:01:21 -05:00
Sandor Dornbush 4a47c096f7 Possible fix for chart view. 2011-02-04 10:41:17 -08:00
Olivier Beyssac bd961be055 Updating French translations. 2011-02-04 16:25:54 +00:00
boiledorange73 525fea80b8 One entry went back... Corrects it. 2011-02-04 10:44:18 +09:00
boiledorange73 6f92ae6a59 JP translate : Deleted duplicated entries in strings.xml 2011-02-04 10:40:56 +09:00
boiledorange73-201102 91cca16f40 JP trans: small change (LAST) 2011-02-03 00:18:52 +09:00
boiledorange73 a0697a048d JP translate: small changes 2011-02-02 16:48:38 +09:00
boiledorange73 d22c6aae79 JP translate 2011-02-02 15:15:48 +09:00
Rodrigo Damazio 83997980ba Merging German translation 2011-02-02 01:19:40 -02:00
Rodrigo Damazio 163a73722e Fixing translation leftovers from Fusion Tables and other changes.
The strings that need updating are commented-out, as a reference to translators.
(many other strings are simply missing, I didn't do anything about those)
2011-02-01 21:39:26 -02:00
marian.steinbach 65d17decb8 Added missing labels 2011-02-01 09:06:29 +01:00
Sandor Dornbush 1aa300f97e Merge in Rodrigo's changes. 2011-01-31 20:39:15 -08:00
marian.steinbach 8fbb30bded Added some missing ANT-related labels, deleted obsolete sensor labels, changed 'Energie' (power) to 'Kraft' 2011-01-31 23:37:04 +01:00
Sandor Dornbush 9ff370ee27 Clean up zh-cn strings.xml 2011-01-30 21:49:43 -08:00
Sandor Dornbush cd0057ea5a A bunch of fusion tables fixes. 2011-01-30 21:39:43 -08:00
Sandor Dornbush 2c0a294b6a A bunch of fusion tables fixes. 2011-01-30 21:39:27 -08:00
Rodrigo Damazio 3e09bd5c60 Fixing ProGuard support by removing usage of reflection and ignoring a few unused classes. 2011-01-30 01:20:37 -02:00
Rodrigo Damazio 0a99d7cebb Changing AndroidMock config to look for API level 9 classes. 2011-01-29 22:26:26 -02:00
Sandor Dornbush 3138e3edc7 Remove reference to old string. 2011-01-27 23:11:15 -08:00
Sandor Dornbush 99ab34ad0b Merge spanish update. 2011-01-23 21:38:56 -08:00
Sandor Dornbush 9b7923f8f5 Merge Matthew's changes. 2011-01-21 22:21:39 -08:00
Matthew Simmons cfcbe7f107 Refactor platform adapter logic 2011-01-21 18:22:41 -05:00
Matthew Simmons 5fb27ab186 Bump the database version, update the migration code 2011-01-21 17:54:37 -05:00
Matthew Simmons 36b1a3c020 Rename locatePlatformAdapter to createPlatformAdapter 2011-01-21 17:22:30 -05:00
Matthew Simmons baccb5d12e Use reflection to find the platform adapters 2011-01-21 17:09:25 -05:00
Matthew Simmons adc4621711 self-review 2011-01-21 16:32:27 -05:00
Matthew Simmons a8d78664e9 Added support for backing up sensors 2011-01-21 16:28:04 -05:00
Sandor Dornbush 9fab4eb088 Update spanish translation. 2011-01-19 22:41:50 -08:00
Sandor Dornbush 0d0f1315ff Add spain spanish translation. 2011-01-19 22:28:46 -08:00
Sandor Dornbush 555598c155 Only show sensor options for the right sensor type. 2011-01-13 21:28:10 -08:00
Sandor Dornbush f49fa23f69 Merge from head. 2011-01-13 21:07:15 -08:00
Rodrigo Damazio b732064f88 Moving assets to their own repository. 2011-01-13 22:26:44 -02:00
Rodrigo Damazio 1f99a381eb Merging Fusion Tables changes. 2011-01-13 22:23:51 -02:00
Sandor Dornbush 81b610cc4c Change the code to use the new icons + delete the old icon files. 2011-01-13 15:17:20 -08:00
marian.steinbach b0a0bfc888 Simplified icons for Record Track and Stop Recording, both drawable and assets 2011-01-12 19:53:52 +01:00
marian.steinbach 6221ccb53b Merging changes from main repository 2011-01-12 19:17:47 +01:00
leifhendrik cbe1da2d68 Keeping db version 18. Bug fixes. 2011-01-11 15:01:44 -08:00
Sandor Dornbush 24297e373c Merging to head + return early to fully ignore close locations. 2011-01-11 14:06:06 -08:00
leifhendrik 99d14a559c Synced with head. Resolved conflicts. 2011-01-11 13:30:03 -08:00
leifhendrik 08339a1f65 String cleanups and responded to most comments. 2011-01-11 12:29:22 -08:00
Rodrigo Damazio 4e3ad38087 Merging Matthew's changes. 2011-01-10 15:41:41 -02:00
Sandor Dornbush 63c97fadc6 Merge in SendToDocs changes. 2011-01-09 22:21:03 -08:00
Matthew Simmons 45633ad7e8 Code review comments 2011-01-07 14:43:25 -05:00
Matthew Simmons 8508decd5c fix url 2011-01-07 14:04:59 -05:00
Matthew Simmons 315f47bf30 Add License button to the About dialog box.
Add link to privacy policy to the About dialog box.
2011-01-07 13:22:30 -05:00
Matthew Simmons 12f8d79d84 unconcatenate constant 2011-01-06 15:42:05 -05:00
Rodrigo Damazio 710690e2d2 Merging to head. 2011-01-06 18:00:11 -02:00
Rodrigo Damazio 03bfbe81d0 Merging Sandor's change. 2011-01-06 15:08:42 -02:00
Matthew Simmons c990fb6fe7 don't hardcode the encoding in the tcx writer either 2011-01-06 11:53:10 -05:00
Sandor Dornbush 9b31cd63a4 Fix overcounting distance. 2011-01-05 22:58:53 -08:00
Rodrigo Damazio dee3ccdf77 Cleaning up deps 2011-01-05 23:09:16 -02:00
Matthew Simmons de23a32c96 Write the VM's charset in the GPX file's XML header, rather than using a
hard-coded value.  Per the Android docs, the default charset for Android is
UTF-8.
2011-01-05 19:54:49 -05:00
Matthew Simmons 2beb840a5c Code review 2011-01-05 18:26:01 -05:00
Matthew Simmons f748d76549 Move the methods which initiate the SendToDocs GData calls into their own class.
This makes SendToDocs easier to understand and easier to test.
2011-01-05 17:16:01 -05:00
Rodrigo Damazio 9d9a326c2b Merging Bart's fix. 2011-01-05 17:00:12 -02:00
marian.steinbach 9184827195 Pre-production files for menu icons (second attempt) 2011-01-05 09:08:51 +01:00
marian.steinbach cb533c954b Merged remote changes 2011-01-05 09:00:36 +01:00
marian.steinbach ead876036d Removing icons from /MyTracks/assets 2011-01-05 08:48:12 +01:00
Sandor Dornbush cfa25eccb1 Fix export all TCX. 2011-01-04 21:57:49 -08:00
Sandor Dornbush b0d6233de6 Merge from head and address comment. 2011-01-04 21:00:12 -08:00
bartn b07b8a1aaa Fix broken test and avoid mocking provider. 2011-01-04 16:19:32 -08:00
leifhendrik a68cdaf2ba More cleanups. Towards a working solution. 2011-01-04 10:11:03 -08:00
marian.steinbach 16641b9193 Pre-production files for menu icons 2011-01-04 09:10:30 +01:00
Sandor Dornbush 0469a90992 Merging from head. 2011-01-03 16:47:35 -08:00
Sandor Dornbush 6dc3e5ab7a Remove trailing white space. 2011-01-03 16:44:34 -08:00
Rodrigo Damazio 82012fa623 Merging from head. 2011-01-03 13:05:30 -02:00
marian.steinbach 7ddd254bb1 Added various missing strings, modified some existing translations 2011-01-03 00:37:56 +01:00
marian.steinbach 464858cfdf Slight comment clean-up 2011-01-03 00:37:12 +01:00
marian.steinbach 30db23255d New menu icons (according to pre-2.3-guidelines) 2011-01-02 22:50:02 +01:00
Sandor Dornbush 868c1ef891 Merge from head. 2010-12-31 09:14:09 -08:00
Sandor Dornbush b961356b7b Addressed comments.
Merge from head.
2010-12-31 09:11:22 -08:00
bartn 2e32d6c574 Address comments and fix broken test. 2010-12-31 00:15:12 -08:00
bartn a31e5aab79 Address comments. 2010-12-30 19:46:14 -08:00
bartn ae4f9565bd Chart drawing refactoring, part 1. Better handle label drawings for multiple data series, fix a few bugs and introduce fine grained zoom settings. 2010-12-29 17:52:23 -08:00
bartn f33ba10b96 Merge with 5ad4c64449adf707f3a0619d568deac185e7ff05 2010-12-28 17:14:37 -08:00
Sandor Dornbush 904c519091 Move untranslated strings to a new resources file. 2010-12-28 17:01:23 -08:00
bartn a0db837910 Merge with 0d6e42a25349b4c1099e8a03a37e22cc559da048 2010-12-28 16:58:56 -08:00
Sandor Dornbush 51cb5db8b4 Add ANT+ sensor support. 2010-12-28 16:29:26 -08:00
bartn c328728e0c Use LocationIterator for scalability and instantiate MyTracksLocation to make sure that sensor data is properly read. 2010-12-28 16:19:34 -08:00
Sandor Dornbush 3384ef67a6 Addressed comments. 2010-12-28 14:39:26 -08:00
bartn e89c549706 Merge with 6f18dfaa4b33c178829a3cdfa374f0ac6a55d5c7 2010-12-28 11:17:43 -08:00
leifhendrik 3c67ac73da Support uploading of tracks to fusion tables. Remove support for maps data api. 2010-12-28 10:40:49 -08:00
Sandor Dornbush 656349e6c5 Use scaled pixels for chart view.
Use better colors for sensor data.
2010-12-27 09:06:08 -08:00
Rodrigo Damazio df2af0185c Using preferences' apply() instead of commit() on Gingerbread. 2010-12-24 05:41:03 -02:00
Rodrigo Damazio 913d30f2de Merge from head 2010-12-24 05:27:56 -02:00
Hauke Ingmar Schmidt e96172b698 * Fixed some typos. 2010-12-23 16:25:34 +01:00
Hauke Ingmar Schmidt 0c241f683d * Did a cross check with current english file, added keys
* Stoppen->Anhalten
*
2010-12-23 15:04:10 +01:00
bartn a19097de2b Get rid of unused getTrackPoints(...). 2010-12-22 16:54:13 -08:00
bartn f6feeb9d1e Fix a typo. 2010-12-22 16:03:10 -08:00
bartn f205e6f9cc Make sure we don't upgrade twice on newer DBs. Prepare for upcoming DB changes v19. 2010-12-22 16:02:05 -08:00
bartn 4e543e6068 Merge with f31f08b12616cde71b9f6df34a92a66c35140d92 2010-12-22 15:30:47 -08:00
bartn 176062f11c Address comments (round #2). 2010-12-22 14:39:04 -08:00
bartn 4d88191171 Address comments. Use bulkInsert to improve performace (2min for 20K points before vs. 10 sec now). 2010-12-22 14:24:26 -08:00
Sandor Dornbush 025ea1d094 Address comments. 2010-12-21 09:31:54 -08:00
bartn a4283d545a Add missing Java class with unit tests. 2010-12-20 14:51:00 -08:00
bartn 52fa2aace9 Finalize the new interface, fix bugs and add unit tests. 2010-12-20 14:50:27 -08:00
Sandor Dornbush fa711cf142 Address comments + add more tests. 2010-12-19 22:11:41 -08:00
bartn 70bc7e53fe Fix a bug in getLocationIterator 2010-12-17 15:09:58 -08:00
bartn 56f22aa073 Addressed comments + new method getLocationId() 2010-12-17 13:57:51 -08:00
Sandor Dornbush 878a87278d Address comments. 2010-12-17 06:59:43 -08:00
bartn c4a539d2ba Initial implementation of getLocationIterator 2010-12-16 21:09:12 -08:00
bartn 4225e81080 Added missing change. 2010-12-16 17:58:28 -08:00
bartn 8fd4887f10 Merge with c31ef4ac66823a80d02265da7810432b51ce01ed 2010-12-16 17:49:01 -08:00
bartn 0e397797b4 Addressed Rodrigo's comments. 2010-12-16 17:46:27 -08:00
bartn e6c8458ce7 Initial draft of the upcoming changes to simplify track points management. 2010-12-16 14:13:09 -08:00
bartn 50ea9919af Add myself to the About box, as suggested by Rodrigo. 2010-12-16 12:31:35 -08:00
Sandor Dornbush 67f62df894 Fix a few bad characters in Catalan files. 2010-12-16 08:35:16 -08:00
Sandor Dornbush 0da0280156 Address one last comment. 2010-12-15 16:53:38 -08:00
Sandor Dornbush fa713eac4a Address comments. 2010-12-15 16:49:37 -08:00
Sandor Dornbush 2c7d56ab34 Adding Catalan translation. 2010-12-15 08:49:02 -08:00
Sandor Dornbush e340268dd0 Minor fixes and respond to comments. 2010-12-13 22:34:58 -08:00
Sandor Dornbush affec6720b Update tests.
Lazily allocate stats objects on waypoints.
2010-12-12 20:02:12 -08:00
Sandor Dornbush 5047826a74 Minor fixes. 2010-12-11 22:06:55 -08:00
Sandor Dornbush 33d9230442 Refactor the waypoint insertion code. 2010-12-11 19:14:47 -08:00
Rodrigo Damazio 607b174c5f Fixing some StrictMode violations, making it softer for others which the Android runtime itself triggers. 2010-12-10 16:40:22 -02:00
Rodrigo Damazio 6b4ea71404 Enabling Proguard to reduce APK size. 2010-12-10 15:39:48 -02:00
Rodrigo Damazio 014322c240 Updating new projects to API level 9 and adding xlarge screen size support. 2010-12-10 14:41:21 -02:00
Rodrigo Damazio b789f84151 Adding new method required in Gingerbread. 2010-12-10 14:36:24 -02:00
Rodrigo Damazio 19d5fe1ba6 Merging gingerbread changes to head. 2010-12-10 14:30:29 -02:00
Rodrigo Damazio 93b95954c4 Updating to API level 9 2010-12-10 14:28:25 -02:00
Rodrigo Damazio fb7a2aaa32 Enabling strict mode in non-release builds 2010-12-10 14:28:11 -02:00
Rodrigo Damazio 3105eacd4d Adding Gingerbread platform adapter 2010-12-10 14:26:14 -02:00
Rodrigo Damazio 215893214f Merging sensor and library changes together. 2010-12-07 18:04:28 -02:00
Bartlomiej Niechwiej 30e01d6700 Revert back local changes. 2010-12-04 23:54:53 -08:00
Bartlomiej Niechwiej 94cfc5d7d6 Merge with 3af20c63ed16c56b6e5e3d854272ec1fb8074570 2010-12-04 23:50:16 -08:00
Sandor Dornbush 471b32cce1 Fix announcement available setting. 2010-12-03 13:11:56 -08:00
Bartlomiej Niechwiej 036b34e91d Fix upgrade SQL. 2010-12-03 00:43:00 -08:00
Bartlomiej Niechwiej 77f7f8c1ed Merge with c6c03f517e6dc6d0da60ace9bd21311c9b20f4dc 2010-12-03 00:35:44 -08:00
Bartlomiej Niechwiej e6fc991d2a DO NOT PULL (local changes) 2010-12-03 00:35:25 -08:00
Sandor Dornbush 060881777d A few more minor fixes. 2010-12-01 20:37:11 -08:00
Sandor Dornbush 6e567fa725 Fix broken build and add icon for sensor state. 2010-12-01 17:56:28 -08:00
Sandor Dornbush 7e4c01937f Minor fixes. 2010-12-01 17:28:22 -08:00
Sandor Dornbush 06a00e6482 Merge from head + bug fixes. 2010-12-01 14:24:47 -08:00
Bartlomiej Niechwiej 242df42f55 Fixed a few NumberFormatExceptions as found in the market reports. 2010-11-28 17:44:37 -08:00
Rodrigo Damazio 8d78c16c8a Adding more tests and other minor fixes. 2010-11-28 03:37:27 -08:00
Rodrigo Damazio db2b05eb7f Moving more constants to the library. 2010-11-28 03:17:24 -08:00
Rodrigo Damazio 282b1090ba Merging from head 2010-11-28 03:00:51 -08:00
Rodrigo Damazio 4f6c9fa866 Creating a library to hold code and resources common to both My Tracks and third-party apps. 2010-11-28 02:35:30 -08:00
Rodrigo Damazio 9375842c71 Moving intent constants to XML file. 2010-11-28 00:48:05 -08:00
Rodrigo Damazio ea3fca0f1b Addressing review suggestions for third-party apps. 2010-11-27 02:52:04 -08:00
Rodrigo Damazio 5971d67a66 Moving signal strength sampling into a separate app. 2010-11-26 23:51:32 -08:00
Rodrigo Damazio 357b68dd4f Merging 1.0.21 changes back to the default branch 2010-11-26 15:00:41 -08:00
Rodrigo Damazio 384f3f5698 Added tag v1.0.21 for changeset f9230d18271a 2010-11-26 14:57:35 -08:00
Rodrigo Damazio 4577ff9628 Releasing 1.0.21 2010-11-26 14:57:03 -08:00
Rodrigo Damazio e6cd9f524d Replacing tabs with spaces 2010-11-24 19:21:29 -08:00
Rodrigo Damazio 3dad56621f Transplanting Sandor's bugfix change for dialogs in old devices. 2010-11-24 18:57:40 -08:00
Rodrigo Damazio 6c9a225b64 Merging Bart's changes into the bugfix branch. 2010-11-24 18:27:40 -08:00
Rodrigo Damazio 3bbb9bd95d Making a 1.0.20 bugfix branch 2010-11-24 18:26:30 -08:00
Bartlomiej Niechwiej a4f855ccd8 Addressed Rodrigo's comments. 2010-11-24 16:26:12 -08:00
Bartlomiej Niechwiej 4d80af4e06 An emergency fix for a NPE in the service. 2010-11-24 15:46:57 -08:00
Rodrigo Damazio 7abce12499 Merging from head. 2010-11-23 22:13:01 -08:00
Rodrigo Damazio 7b1302c011 Adding broadcasts for when we start/stop recording.
Pause/resume constants are there so apps consider them, but not yet implemented.
2010-11-23 22:12:16 -08:00
Rodrigo Damazio 66d23b7eac Fixing permission descriptions so they show up properly in application manager 2010-11-23 22:11:04 -08:00
Rodrigo Damazio dc0255509b Adding permissions for third-party apps. 2010-11-23 21:53:59 -08:00
Rodrigo Damazio 6661f91eb5 Added tag v1.0.20 for changeset b259d09396e5 2010-11-23 15:20:15 -08:00
Rodrigo Damazio 2eb36aedeb Releasing version 1.0.20. 2010-11-23 15:18:39 -08:00
Bartlomiej Niechwiej 0e623ebfeb Fix a memory leak that was observed each time a recording session was stopped. 2010-11-21 23:49:17 -08:00
Rodrigo Damazio ffb73569e9 Merging Bart's fixes. 2010-11-21 21:11:35 -08:00
Bartlomiej Niechwiej 713cda9455 Addressed Rodrigo's comment. 2010-11-21 21:07:59 -08:00
Bartlomiej Niechwiej 223721cca8 Nullify bineder/checkListener on destroy. 2010-11-21 20:55:44 -08:00
Rodrigo Damazio e7479c8a93 Fixing periodic task restarting. 2010-11-21 20:45:25 -08:00
Bartlomiej Niechwiej 224fe0069b Make sure there is only one instance of TrackRecordingService at a time. 2010-11-21 19:33:14 -08:00
Rodrigo Damazio cb97847392 Addressing comments from a475cd4d33. 2010-11-21 00:44:34 -08:00
Rodrigo Damazio 6a29531467 Second attempt at proper task startup. 2010-11-20 16:21:59 -08:00
Rodrigo Damazio 262e249d2c Also fixing splitter initialization, just for completeness. 2010-11-20 05:46:38 -08:00
Rodrigo Damazio 77479efaef Fixing TTS initialization. 2010-11-20 05:43:09 -08:00
Rodrigo Damazio 898863a8d9 Merging Sandor's second head by ignoring it 2010-11-19 18:37:27 -08:00
Sandor Dornbush 05d555f98d Fix the end track confirmation dialog. 2010-11-19 17:23:27 -08:00
Rodrigo Damazio 868092db10 Fixing intiialization before context is available. 2010-11-19 14:26:11 -08:00
Rodrigo Damazio 7a738c2eca Moving the end recording method to more reasonable location. 2010-11-18 17:14:56 -08:00
Rodrigo Damazio b304dbcba6 Fixing wake lock being held for too long in the service. 2010-11-18 17:13:20 -08:00
Rodrigo Damazio 6e28a5daa4 Merging Matthew's fix for issue 137. 2010-11-18 16:41:21 -08:00
Bartlomiej Niechwiej 8f4f9660ed Addressed Sandor's comments. 2010-11-18 15:42:02 -08:00
Bartlomiej Niechwiej 2d01535651 Fixed a NPE introduced after refactoring dialogManager. 2010-11-17 22:39:50 -08:00
Bartlomiej Niechwiej e57d4669fc Revert API key changes. 2010-11-17 22:25:20 -08:00
Bartlomiej Niechwiej f47c599dea Merge with 63eb7915dafe329e8f06cc33c56122ee15ea6df7 2010-11-17 22:20:15 -08:00
Bartlomiej Niechwiej 7a693a90f7 Make the app single process only, including the following fixes:
1) Simplify SharedPreferences management
2) Shut down signalManager/splitManager to avoid random crashes
3) Get rid of sharedPreferencesChanged from the service interface

All tests pass.
2010-11-17 22:18:50 -08:00
Bartlomiej Niechwiej 9cf51de3f7 Fix a typo in onDestroy. 2010-11-17 20:07:34 -08:00
Matthew Simmons 5089c20cd6 Code review fixes 2010-11-16 11:39:08 -05:00
Bartlomiej Niechwiej a0da23f86a Various fixes to shared preferences. 2010-11-15 23:09:18 -08:00
Rodrigo Damazio 44d24b57c6 Making telephony support optional. 2010-11-15 22:04:48 -08:00
Rodrigo Damazio c143d774d4 Merging Aaron's changes. 2010-11-15 21:50:46 -08:00
Matthew Simmons 9e92240dd0 More self-review 2010-11-15 21:46:19 -05:00
Sandor Dornbush d2c586b096 Fix StatusAnnouncer thread for initialization and prefs in service. 2010-11-15 18:20:10 -08:00
Matthew Simmons fbfbb9408a Self-review 2010-11-15 18:46:23 -05:00
Matthew Simmons fb56665dec Rework authorization failure retry. The retry needs to be synchronous with
the original runone.
2010-11-15 18:37:42 -05:00
Bartlomiej Niechwiej 5b65c216b6 More tests. 2010-11-12 22:18:38 -08:00
Rodrigo Damazio 9ad98c5970 Merging Sandor's changes 2010-11-12 14:37:04 -08:00
Aaron Brown cae9d0f2e5 updated MyTracks/AndroidManifest.xml for inclusion of uses-feature 2010-11-12 17:11:56 +10:00
Sandor Dornbush c0d267c63e Minor formating fixes. 2010-11-11 21:41:39 -08:00
Sandor Dornbush 70704b0a5e Move navcontrols icon decleration to xml. 2010-11-11 21:38:24 -08:00
Sandor Dornbush b135275201 Minor fix for dialog manager. 2010-11-11 16:15:11 -08:00
Bartlomiej Niechwiej 7e1eae6681 Addressed Sandor's comments and added more unit tests and fixed 2 NPEs. 2010-11-11 10:55:15 -08:00
Bartlomiej Niechwiej 30f5d6dc85 Fix two NPEs and add more test coverage. 2010-11-11 00:31:56 -08:00
Sandor Dornbush a50dd1168b Fix format error. 2010-11-09 13:57:19 -08:00
Sandor Dornbush 62fa1620aa Actually add the dialog tests. 2010-11-08 11:31:14 -08:00
Sandor Dornbush a0d42c8b59 Add basic tests to the DialogManager. 2010-11-08 11:28:39 -08:00
Bartlomiej Niechwiej a21663da61 Fix a NPE (replace MyTracks.getInstance() with the parent activity). 2010-11-06 23:37:14 -07:00
Bartlomiej Niechwiej 67a0382942 Fixed another bug reported by users (division by zero).
The issue was most likely related to a race condition (selectedTrackId can change in the UI thread, while the track is being processed in the handler thread).

Simulated slow drawing by adding 50ms, works pretty cool :)
2010-11-06 00:31:52 -07:00
Bartlomiej Niechwiej f5c2467d01 Fix StringIndexOutOfBoundsException in ChartsExtendedEncoder.getEncodedValue().
Found in user error reports (3rd top issue):
java.lang.StringIndexOutOfBoundsException
at com.google.android.apps.mytracks.util.ChartsExtendedEncoder.getEncodedValue(ChartsExtendedEncoder.java:45)
at com.google.android.apps.mytracks.util.ChartURLGenerator.getChartUrl(ChartURLGenerator.java:162)
at com.google.android.apps.mytracks.util.ChartURLGenerator.getChartUrl(ChartURLGenerator.java:60)
at com.google.android.apps.mytracks.util.StringUtils.generateTrackDescription(StringUtils.java:366)
at com.google.android.apps.mytracks.io.SendToMyMaps.doUpload(SendToMyMaps.java:581)
at com.google.android.apps.mytracks.io.SendToMyMaps.access$10(SendToMyMaps.java:538)
at com.google.android.apps.mytracks.io.SendToMyMaps$5.run(SendToMyMaps.java:517)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at android.os.HandlerThread.run(HandlerThread.java:60)
2010-11-05 22:52:42 -07:00
Bartlomiej Niechwiej a3abcc8094 Provide a workaround for binding to the service once it has been started. It fixes the failing tests (4). 2010-11-05 20:45:06 -07:00
Sandor Dornbush edf439f301 Merge Bart's bug fixes and tests. 2010-11-05 15:37:20 -07:00
Sandor Dornbush 2245563250 Fix broken build. 2010-11-05 14:51:06 -07:00
Bartlomiej Niechwiej bca21d5515 Addressed Rodrigo's comments. 2010-11-05 10:11:55 -07:00
Bartlomiej Niechwiej 89cae2e7c9 Fix a regression related refactoring recordingTrackId management.
In particular:
1) Add a workaround to {start/end}Recording to update recordingTrackId to trigger a notification
2) Add a bunch of unit tests for MyTracks
3) Clear minor style issues in a few classes
2010-11-04 23:32:31 -07:00
Sandor Dornbush 26c381a4c4 Address Bart's comments and more dialog clean up. 2010-11-04 17:44:08 -07:00
Sandor Dornbush 4bc5aa050c Add tests for the TempFileCleaner. 2010-11-04 17:07:59 -07:00
Rodrigo Damazio cd44b0d180 Merging Sandor's changes. 2010-11-03 21:08:50 -02:00
Rodrigo Damazio 59ee91ca5d Merging my own changes. 2010-11-03 20:59:32 -02:00
Rodrigo Damazio 59165a7033 Ignoring Matthew's second head by no-op merging it. 2010-11-03 20:53:50 -02:00
Rodrigo Damazio 93d242c05f Merging Matthew's first head. 2010-11-03 20:42:35 -02:00
Rodrigo Damazio 4bbb6591e3 Merging Bart's changes. 2010-11-03 19:59:35 -02:00
Sandor Dornbush 7df8025f6a Merge with head and address comments. 2010-11-03 12:53:12 -07:00
Bartlomiej Niechwiej f19c52f40e Addressed Sandor's comments. 2010-11-02 08:31:21 -07:00
Bartlomiej Niechwiej b7840779fe Revert API Key Change. 2010-11-02 08:26:31 -07:00
Rodrigo Damazio 28042a8cc9 Adding tests to voice announcements.
If anyone asks, I didn't write this code.
2010-11-02 02:19:43 -02:00
Matthew Simmons b2907226bf Code review comments 2010-11-01 15:21:33 -04:00
Matthew Simmons a2f46821f5 Fix author line 2010-11-01 14:32:19 -04:00
Matthew Simmons b7385cd4cc Combine b2f2f9e9e9 and 8774b3663c
Allow users to choose the default track name policy.  By default, we'll switch
to a new, timestamp-based name.  If they change the pref, they'll get the
old-style 'track n' style.
2010-11-01 13:48:33 -04:00
Matthew Simmons 718c65818c Allow users to choose the track name policy. 2010-11-01 12:59:56 -04:00
Rodrigo Damazio 91e2293606 Adding proper AndroidMock configuration - requires setting eclipse variables 2010-11-01 05:30:16 -02:00
Rodrigo Damazio 3c4a921f9a Addressing review suggestions 2010-11-01 05:27:04 -02:00
Rodrigo Damazio d04b333126 Merging 2010-11-01 02:05:42 -02:00
Rodrigo Damazio 0a4bef4d9a Fixing concurrent access to the content provider by making it have a single instance in the same process as the service. 2010-10-29 17:35:54 -02:00
Bartlomiej Niechwiej a0f090a83a Bug fixing and refactoring:
1) Make sure no one but service changes recordingTrackId (which is owned by it)
2) Cache sharedPreferences
3) Clear recordingTrackId if it doesn't correspond to a valid track or the service is not recording
4) More unit tests
2010-10-28 22:49:01 -07:00
Bartlomiej Niechwiej dc8ee5943c Merge with c10bc69662325f00bf166b783cc3ab1b78ccfed9 2010-10-28 20:48:01 -07:00
Bartlomiej Niechwiej 9132c36aa7 Use a test android:apiKey instead of the official one. 2010-10-28 20:47:42 -07:00
Sandor Dornbush 224c0d759f Minor fixes noticed on first review. 2010-10-28 17:13:59 -07:00
Sandor Dornbush ffcaca2db1 Refactor a few 100 lines of code out of the main Activity. 2010-10-28 17:08:59 -07:00
Sandor Dornbush 409fc4a43b Address Bart's comments. 2010-10-28 15:07:01 -07:00
Sandor Dornbush 16968f3f2b Fix copyright notice. 2010-10-28 14:50:03 -07:00
Sandor Dornbush e3fd0dce21 Undo changes to the eclipse prefs. 2010-10-28 14:47:00 -07:00
Sandor Dornbush 53b6b6deca Add tests to ChartValueSeries.
Also other minor fixes.
2010-10-28 14:43:31 -07:00
Rodrigo Damazio 26f47a50d0 Fixing issue 34: Not making voice announcements during a phone call 2010-10-27 03:07:17 -02:00
Bartlomiej Niechwiej 3cf77374c4 Fix merge. 2010-10-26 20:19:54 -07:00
Bartlomiej Niechwiej a1129c3f0f Merge with c58e4b8519d3ed6959a96192286b83aa1b77f6f3 2010-10-26 20:17:15 -07:00
Bartlomiej Niechwiej 2fe74603a3 Merge with 96ee47b2d8639a0cf62a387f3360640643fbeb0a 2010-10-26 20:14:41 -07:00
Bartlomiej Niechwiej 54d517363d Merge with e34329d612571554d6424d5941dfad57e35612a0 2010-10-26 19:39:46 -07:00
Bartlomiej Niechwiej 948fe0c0e6 Merge with 68eb8dff3a87698ace057447dff40a07cf673f2e 2010-10-26 19:39:20 -07:00
Bartlomiej Niechwiej dbd8e6c0e9 Merge with 5ed61c63ba59f4748231ea14bbbc222423d0b08a 2010-10-26 19:38:51 -07:00
Bartlomiej Niechwiej 02b5601933 Remove unnecessary log. 2010-10-26 19:32:24 -07:00
Sandor Dornbush 3ed40608a2 Merging from head. 2010-10-26 14:44:31 -07:00
Bartlomiej Niechwiej 36d7c2dd91 Allow to move the app to SD card (by default goes to internal storage). This is a frequently requested feature (based on market feedback). 2010-10-26 00:33:38 -07:00
Bartlomiej Niechwiej fa7ef68851 Addressed Sandor's comments. 2010-10-25 22:35:38 -07:00
Matthew Simmons f84877a4fc Issue 86: Remove - from the list of disallowed characters for filenames. 2010-10-25 14:59:20 -04:00
Matthew Simmons 261fb62e24 Changed the default new track name from "track %d" to "date time", where "date"
is a short, locale-aware version of the track's start date, and "time" is the
track's start time.
2010-10-25 14:15:16 -04:00
Bartlomiej Niechwiej 48d8aa4cd8 Introduce an interface to decouple platform specific API from the classes that require it. Also:
1) Put the service into foreground to prevent from being killed by the system
2) Fix a bug the prevented MyTracks from running on pre-Eclair devices
2010-10-24 21:24:11 -07:00
Bartlomiej Niechwiej 95ff0d3db6 Fix a typo in shared preferences and minor cleanup. 2010-10-24 18:55:35 -07:00
Bartlomiej Niechwiej 2dc1d914c0 Several fixes to the service and more test coverage.
Notably:
1) Fixed isRecording to not return false if service is down (for instance, it may be being restarted)
2) Added more checks to prevent from invalid starting/stopping (if in already in progress/not started).
2010-10-24 14:16:43 -07:00
Bartlomiej Niechwiej fc06701009 Fix several bugs and clean up statistics management.
1) Decouple clock from TripStatisticsBuilder.
2) Introduce a new param to constructor to automatically resume at given time
3) Fix various statsbuilder initialization issues in the service (wrong order, missing initialization)
2010-10-24 03:30:58 -07:00
Bartlomiej Niechwiej ee4f334296 Fixed a NPE under certain circumstances (move initialization to onCreate()). 2010-10-24 03:26:32 -07:00
Bartlomiej Niechwiej cac2395237 More unit tests for TracksRecordingService and fix a few bugs. Made the service less forgiving rather than silently ignoring invalid state. 2010-10-24 00:48:53 -07:00
Bartlomiej Niechwiej 5afc3f13cf Minor refactoring: remove dependency on Context and replace it with ContentResolver. 2010-10-23 19:04:57 -07:00
Rodrigo Damazio 9030917c14 Merging Bart's changes. 2010-10-22 15:34:24 -02:00
Bartlomiej Niechwiej 9905def352 Terminate tracker update thread on destroy. 2010-10-22 10:14:36 -07:00
Bartlomiej Niechwiej a3793aa92b Minor updates. 2010-10-22 10:00:15 -07:00
Nulled 76c8498956 updated zh-cn translation 2010-10-21 17:51:40 +08:00
Nulled 75bd8ea5a2 Updated zh-cn translation. fixed some errors. 2010-10-15 18:15:43 +08:00
Nulled 50a5e864ac updated zh-cn translation 2010-10-15 18:04:56 +08:00
Rodrigo Damazio 352fc26f7e Fixing tests 2010-10-14 23:25:42 -03:00
Rodrigo Damazio 44afa1623e Making locations be reused when writing tracks. 2010-10-14 21:06:59 -03:00
Rodrigo Damazio 14acafabfc Getting rid of TrackBuffer. 2010-10-14 20:42:02 -03:00
Rodrigo Damazio 773af58d03 Fixing issue 190 (third step: reordering methods in execution order - no other changes) 2010-10-14 18:44:55 -03:00
Rodrigo Damazio 352b851e9c Fixing issue 190 (second step: refactoring mymaps uploading) 2010-10-14 18:35:51 -03:00
Rodrigo Damazio 8353a01082 Addressing review suggestions. 2010-10-14 16:41:20 -03:00
Bartlomiej Niechwiej b70e001206 Addressed Rodrigo's comments. 2010-10-13 21:58:26 -07:00
Rodrigo Damazio a741bb4d55 Fixing issue 190 (first step: dirty hack) 2010-10-13 22:03:31 -03:00
Rodrigo Damazio 24adee3d54 Addressing review suggestions and adding tests. 2010-10-13 21:53:16 -03:00
Bartlomiej Niechwiej 09203ffb95 Improved test coverage and minor refactoring/improvements. 2010-10-13 12:29:00 -07:00
Bartlomiej Niechwiej e94338f4c6 Fix a drawing lag during track recording.
For a track with ~2,500 points, the average drawign would take ~30-50ms, now it takes about 20ms (21ms if software clipping is enabled).

Removed all possible congestion points by introducing a blocking queue.

This change includes many fixes, including:
1) Major refactoring and clean up of the overlay, sped up drawing by a factor of 2x
2) Disable software clipping as it was slower by about 5% than w/o clipping and would trigger a bug related to map view spanning
3) Add waypoints synchronization  and fixed a bug related to skipping the first wpt
4) Add a simple unit test
2010-10-11 21:55:12 -07:00
Rodrigo Damazio dd9dd8ee81 Refactoring API level detection. 2010-10-11 22:28:02 -03:00
Rodrigo Damazio 01d6dcac59 Merging Bart's Polish fix. 2010-10-07 21:59:11 -03:00
Rodrigo Damazio ad0ee6b0d6 Merging Bart's Polish fix. 2010-10-07 21:58:07 -03:00
Rodrigo Damazio 769c8c228e Added tag v1.0.19 for changeset b096086934d6 2010-10-07 21:21:52 -03:00
Rodrigo Damazio 50fcd67085 Releasing version 1.0.19 (bugfix release) 2010-10-07 21:21:23 -03:00
Sandor Dornbush 52d03e6b7d Address Rodrigo's comments. 2010-10-07 16:28:42 -07:00
Sandor Dornbush b949cd0039 Really fix bug. 2010-10-07 12:39:05 -07:00
Sandor Dornbush e527170315 Fix recording error. 2010-10-07 12:01:32 -07:00
Sandor Dornbush ec7d210c36 Fix recording error. 2010-10-07 11:51:54 -07:00
Bartlomiej Niechwiej 74a4089464 Fix incorrect Polish translation related to delete track(s)/marker confirmation dialog (Issue 176). 2010-10-07 11:36:39 -07:00
Rodrigo Damazio fa9e14f574 Added tag v1.0.18 for changeset 7c67cd917be3 2010-10-05 17:12:20 -03:00
Rodrigo Damazio cdbeefcd16 Releasing version 1.0.18 2010-10-05 17:11:52 -03:00
Rodrigo Damazio ffdd5f4091 Merging Bart's changes 2010-10-05 14:48:43 -03:00
Bartlomiej Niechwiej bb60525780 Rename intent name to be uppercase. 2010-10-05 10:39:07 -07:00
Bartlomiej Niechwiej 82634af649 Minor refactoring. 2010-10-05 09:47:15 -07:00
Bartlomiej Niechwiej 3643ed9f13 Add missing Polish translations. 2010-10-04 23:07:38 -07:00
Bartlomiej Niechwiej fac59ab705 Partially fix a nasty bug related to losing a tracking session on service crash. 2010-10-04 21:53:34 -07:00
Bartlomiej Niechwiej 1e343b0d12 Limit the maximum number of auto-resume retry attempts to 3. 2010-10-04 21:17:56 -07:00
Bartlomiej Niechwiej 34bb467b97 Merge with 25704964a526fcfe09919af8f29c1e526b5409ec 2010-10-04 16:34:38 -07:00
Sandor Dornbush b092525c10 More swedish fixes. 2010-10-04 16:33:25 -07:00
Bartlomiej Niechwiej 256dac3a82 Moved showNotification() outside if clause. 2010-10-03 23:34:19 -07:00
Bartlomiej Niechwiej dfe947f54d Fixed an exception in MyTracks (added isBound), moved resumeState from onStart to onCreate in TrackRecordingService and some minor refactoring. 2010-10-03 23:28:12 -07:00
Andreas Bockert ce09407816 Fixed a number incorrect translation in Swedish language. 2010-10-01 22:33:16 +02:00
Bartlomiej Niechwiej beee6af79d Apply review feedback. 2010-09-30 23:46:47 -07:00
Bartlomiej Niechwiej c282562867 Introduce getLastModified() in Tracks class and fixe a NullPointerException in service if null intent is passed by the system. 2010-09-30 21:54:07 -07:00
Rodrigo Damazio 2aed9b3a33 Fixing track writer test after memory changes 2010-09-29 18:49:13 -03:00
Rodrigo Damazio 210910f21e Merging aggregated statistics change 2010-09-29 18:46:45 -03:00
Bartlomiej Niechwiej 1d666318ae Fix a bug in maybeResumeTrack. Still not sure if it works correctly (need to verify on real device). 2010-09-29 00:33:28 -07:00
Bartlomiej Niechwiej 4df6095089 Implement automatic restart of MyTracks on phone reboot.
In addition fix the following issues/add functionality:
0) Introduce MyTracksReceiver for listening on broadcast messages
1) Remove unnecessary call to VerifyChecker to avoid 403.
2) Clean up TrackRecordingService by adding private methods for common functionality
3) Fix a bug related to not canceling a timer after service was stopped
4) Add a new preference item to control behavior of new functionality
5) Add a unit test for the service (still need to figure out one issue with mocking content resolver).
2010-09-28 22:46:24 -07:00
Rodrigo Damazio d4edcce224 Uncommenting overlooked XML. 2010-09-27 21:42:59 -03:00
Rodrigo Damazio d7c6761841 Addressing comments I originally made on Sandor's change. 2010-09-27 21:02:52 -03:00
Rodrigo Damazio 5733224f8d Merging Sandor's memory footprint improvement 2010-09-27 17:41:34 -03:00
Rodrigo Damazio 22fd5042bc Merging Sandor's memory footprint improvement 2010-09-27 17:37:20 -03:00
Rodrigo Damazio 44a6f2d448 Further improving/fixing drawing, and adding a bounding box for debugging. 2010-09-27 16:14:04 -03:00
Rodrigo Damazio cd9c17f9b3 Fixing leftover from another commit - commenting out testing method. 2010-09-27 16:11:17 -03:00
Rodrigo Damazio dc07bcf0fa Fixing call to HandlerThread.quit() which only exists in API level 5+. 2010-09-27 14:54:36 -03:00
Rodrigo Damazio 248b8fb4fd Fixing bad resource in preferences (only used in 1.5). 2010-09-27 14:53:30 -03:00
Hauke Ingmar Schmidt d5ec7c3001 * Fixed some translation flaws
* Converted usages of formal language into informal language
2010-09-25 16:19:03 +02:00
Sandor Dornbush 35182a1483 Merge changes. 2010-09-23 14:30:44 -07:00
Sandor Dornbush 21b0a517a9 Merged Rodrigo's changes. 2010-09-23 11:07:31 -07:00
Sandor Dornbush 19a770445e Submit my changes before merging. 2010-09-23 11:02:45 -07:00
Rodrigo Damazio c6512f1376 Preparing to further isolate non-UI code from map drawing. 2010-09-22 22:10:36 -03:00
Rodrigo Damazio 2cb3963138 Refactoring track drawing 2010-09-22 22:04:07 -03:00
Sandor Dornbush d05c394c68 Trying to track down the missing end of track bug. 2010-09-21 15:10:56 -07:00
Sandor Dornbush 797de31960 Merging fixes. 2010-09-14 10:52:55 -07:00
Rodrigo Damazio a0af1a811a Added tag v1.0.17 for changeset 4181d0daba76 2010-09-09 20:07:21 -03:00
Rodrigo Damazio 4933b9ce54 Releasing version 1.0.17 2010-09-09 20:06:58 -03:00
Rodrigo Damazio e81c4eb155 Clearly marking the backup feature as a beta. 2010-09-09 20:06:44 -03:00
Rodrigo Damazio b284c8bc56 Fixing Sandor's fix :) 2010-09-08 22:36:59 -03:00
Sandor Dornbush 872d2d4337 Correctly take preference as a long and stop dividing bounds by E6. 2010-09-08 17:36:58 -07:00
Sandor Dornbush 525f1b7781 Fix restarting recording. 2010-09-07 17:18:06 -07:00
Rodrigo Damazio 2f99d8ca62 Fixing GPX importer tests to work on any timezone. 2010-09-07 17:39:38 -03:00
Rodrigo Damazio 7781014cf7 Fixing issue 148 - properly loading bounding boxes, and adding regression tests. 2010-09-07 16:32:46 -03:00
Rodrigo Damazio 2432b36f5d Minor javadoc style fix 2010-09-07 15:47:07 -03:00
Rodrigo Damazio 288aa015fa Merging GPX import fix 2010-09-07 15:08:54 -03:00
Rodrigo Damazio 1cb8b922c3 Fixing GPX import (issue 150) by properly parsing timestamps according to XML spec. 2010-09-06 23:05:09 -03:00
Rodrigo Damazio 41cec64bf6 Translating overlooked strings to Chinese 2010-09-02 21:06:37 -03:00
Rodrigo Damazio d82bda9d00 Merging Chinese translation 2010-09-02 20:56:31 -03:00
FNelson b84da40365 Merge with 28a6c6c0e8f12e489fa501609be4b564eb822f55
(Merge to Head)
2010-09-02 12:23:32 +01:00
Rodrigo Damazio d02c947b84 Style fixing 2010-09-01 17:46:36 -03:00
Rodrigo Damazio 7167a5a71e Final touches to cloud backup: being future-compatible by not using the agent helpers (those manage the backup state themselves, and we don't want to have to follow their format) 2010-09-01 17:42:14 -03:00
Rodrigo Damazio f13c2455ea Not overwriting files during export, and instead adding a suffix to them.
Also greatly simplifying name sanitization.
2010-09-01 00:03:34 -03:00
Rodrigo Damazio b200b66612 Fixing volume control - making the main activities control the text-to-speech volume. 2010-08-31 18:55:12 -03:00
Rodrigo Damazio b811df8cda Fixing indentation 2010-08-31 17:38:05 -03:00
Rodrigo Damazio 1e239b78c3 Fixing crash seen on developer console.
Basically, if the screen space gets really constrained, we would get a negative dimension for an image.
2010-08-31 17:35:38 -03:00
Rodrigo Damazio 3a8daadd92 Fixing NPE seen on developer console.
Apparently this happens when the activity was previously showing the chart settings dialog, and was paused then restarted - in that case we'll just keep the default chart settings.
2010-08-31 17:31:54 -03:00
Rodrigo Damazio f605d6fca5 Fixing issue 35 - detecting errors during "export all". 2010-08-31 17:14:46 -03:00
Rodrigo Damazio cd85e43624 Merging from head 2010-08-31 16:48:37 -03:00
Nulled 2b94d09539 removed file format array.
minor change to the strings.xml
2010-08-31 09:03:44 +08:00
Nulled ab82da5c75 removed colors.xml 2010-08-31 08:40:40 +08:00
Nulled 8a467aa537 updated chinese translation 2010-08-31 08:39:20 +08:00
Rodrigo Damazio 742e6b1e3e Added tag v1.0.16 for changeset 35854d46e6e4 2010-08-30 18:54:39 -03:00
Rodrigo Damazio e35e8bcdce Updating version number to 1.0.16 in preparation for release. 2010-08-30 18:42:48 -03:00
Rodrigo Damazio 5f953aa47f Fixing version display (missed merge). 2010-08-30 18:36:16 -03:00
Rodrigo Damazio e550e9aa1d Merge 2010-08-30 17:41:35 -03:00
Rodrigo Damazio 26e2defd9e Import cleanup 2010-08-30 17:39:16 -03:00
Sandor Dornbush 3b3641c69e Merging changes from head. 2010-08-27 17:21:33 -07:00
Rodrigo Damazio 56ccd518d6 Adding missing Eclipse configuration files for developers - these have to be manually imported 2010-08-24 22:48:49 -03:00
Rodrigo Damazio 59846280a8 Adding compression to the backup: assuming that backups/restore are infrequent, the added CPU/battery usage is not an issue 2010-08-24 22:39:29 -03:00
Rodrigo Damazio aa95e3abcd Minor leftover cleanup 2010-08-24 21:49:42 -03:00
Rodrigo Damazio ad6340c1a7 BackupActivity doesn't need to be an activity anymore, it has no own content 2010-08-24 21:41:40 -03:00
Rodrigo Damazio 62a54aab58 Style cleanup 2010-08-24 21:34:28 -03:00
Rodrigo Damazio 23f1e81cf0 A lot of cleanup:
* Splitting ExternalFileBackup into UI and non-UI parts
* Disabling backups while recording
* Triggering cloud backups when preferences are changed
2010-08-24 21:27:43 -03:00
Rodrigo Damazio d014f422d2 Ensuring the rest of the app can deal with preferences being restored from the backup 2010-08-24 21:17:55 -03:00
Rodrigo Damazio 68a9f1bc46 Clearing more leftovers from cloud backup. 2010-08-24 20:07:12 -03:00
Rodrigo Damazio 798637d465 Getting rid of full cloud backup for now - the backup service has a small size limit (1MB) which wouldn't be enough for us 2010-08-24 17:38:35 -03:00
Rodrigo Damazio 60ea4c5f77 Merging Sandor's changes with backup (non-trivial merge) 2010-08-24 17:25:50 -03:00
Rodrigo Damazio 0e119950c2 Merging Sandor's changes 2010-08-24 17:02:36 -03:00
Sandor Dornbush 4be4467fc6 Fix NPE. 2010-08-24 12:20:18 -07:00
Sandor Dornbush 06636b2a28 Fix test access modifier. 2010-08-23 09:12:12 -07:00
Sandor Dornbush 71a36d1b25 Address Rodrigo's comments. 2010-08-23 09:05:55 -07:00
Sandor Dornbush 9ba93ff8d2 Fix javadoc. 2010-08-23 08:03:54 -07:00
Sandor Dornbush 4059308dd7 Added comments and license to pref mgr.
Removed sampling from track overlay.
2010-08-22 12:51:40 -07:00
Rodrigo Damazio 9befe8ae5f Reversing backup order 2010-08-20 23:42:51 -03:00
Rodrigo Damazio 20e01f3b2c Storing files in UTC timezone 2010-08-20 23:31:17 -03:00
Rodrigo Damazio 98b894ed8e Adding SD card backup option to the preferences 2010-08-20 23:26:38 -03:00
Rodrigo Damazio ac8b7264b3 Minor initialization fixes 2010-08-20 23:13:05 -03:00
Rodrigo Damazio bf7b24ecc0 Isolating file utilities 2010-08-20 23:10:09 -03:00
sandordornbush 9f43dd2db5 Reverting classpath changes. 2010-08-20 16:11:36 -07:00
sandordornbush 28d868985e One more minor bug fix for a NPE. 2010-08-20 13:32:53 -07:00
sandordornbush cf1be26da2 Two minor bug fixes from the developer console. 2010-08-20 10:51:09 -07:00
Sandor Dornbush 1de9b73aa0 Address Rodrigo's comments.
Add service preference manager.
2010-08-18 22:05:01 -07:00
Rodrigo Damazio 3532a6360b Adding backup facilities. TODO: some tests, calling to trigger new automatic backup on Froyo, manual backup to SD option 2010-08-16 22:22:14 -03:00
Sandor Dornbush beddc8e1ea Add Track Writer test.
Fix total time bug in stats activity.
Fix track segments on the map overlay.
2010-08-16 17:16:43 -07:00
Rodrigo Damazio df81fba565 Fixing directory used in sharing as well 2010-08-16 18:17:14 -03:00
Rodrigo Damazio 25da0d26ef Changing exporters to use a subdirectory of the SD card 2010-08-16 18:14:33 -03:00
Rodrigo Damazio e0c34d20a8 Removing DO NOT TRANSLATE values from Japanese translation 2010-08-16 00:57:03 -03:00
Rodrigo Damazio cc6db5b5cc Merging japanese translation 2010-08-16 00:54:44 -03:00
Rodrigo Damazio c38df03add Ignoring eclipse workspace metadata if present 2010-08-13 13:03:58 -03:00
Rodrigo Damazio 63402358d1 Fixing empty method comment 2010-08-13 04:53:07 -03:00
Rodrigo Damazio 3ae1de735e Removing overlooked debug lines 2010-08-13 04:52:14 -03:00
Rodrigo Damazio a701eb0e4f Fixing 24-hour format mistake 2010-08-13 04:37:37 -03:00
Rodrigo Damazio 09caf017a9 Adding support for segments 2010-08-13 04:37:14 -03:00
Rodrigo Damazio 32b8b2093d REAL performance improvement in importer - using a bulk insertion 2010-08-13 03:50:55 -03:00
Rodrigo Damazio c84a4f1aa8 Moving androidmock to the right directory and making eclipse use it properly 2010-08-12 22:16:38 -03:00
Rodrigo Damazio d90c0b5431 Optimizing the importer a little 2010-08-12 22:14:47 -03:00
Rodrigo Damazio 94f6785f0d Removing no longer used provider utility methods 2010-08-12 22:06:58 -03:00
Rodrigo Damazio f01c382807 Style fixing SAX importer contribution 2010-08-12 20:22:54 -03:00
Rodrigo Damazio 6d42803dd8 Updating statistics object usage in SAX importer 2010-08-12 19:43:27 -03:00
Rodrigo Damazio 61e908ccb5 Merge SAX GPX importer contribution 2010-08-12 18:37:38 -03:00
FNelson 236bcba2bd Changing retrieveAllTracks to getAllTracks 2010-08-12 14:31:03 +01:00
Sandor Dornbush 7bae8c34a7 Integrate most of Rodrigo's comments. 2010-08-11 22:02:49 -07:00
Sandor Dornbush 3960341640 Revert classpath 2010-08-09 16:45:36 -07:00
Sandor Dornbush 06e453dd05 Merging changes from realtime branch into mainline. 2010-08-07 10:38:41 -07:00
FNelson 0347877290 Tidy up to adhere to style guidlines 2010-08-05 12:51:46 +01:00
FNelson b464526d5e Aggregated stats in first working state. 2010-08-04 11:58:43 +01:00
boiledorange73 361b1cbad4 Reverted "DO NOT TRANSLATE" entries 2010-08-04 19:51:00 +09:00
boiledorange73 56a866fca7 Modified bits of values-ja files. 2010-08-04 17:13:35 +09:00
boiledorange73 49e0d68374 res/values-ja added 2010-08-04 14:35:30 +09:00
FNelson 0ccd05e605 First stab at aggregated stats. Still needs work. Check in to work on home computer 2010-07-30 15:04:35 +01:00
FNelson 916e4586c5 First HG commit test. 2010-07-28 10:38:26 +01:00
Sandor Dornbush c9ffd0b4bb Exporting the TrackRecordingService. 2010-07-27 16:34:13 -07:00
Nulled 1d2f6f46a4 Fixed Chinese Simplified translation folder name 2010-06-12 08:09:49 +08:00
Nulled 4af6d856b9 Added Chinese Simplified translation 2010-06-11 08:50:23 +08:00
Steffen Horlacher 6fd4294391 Bugfix for empty total time in trip statistics and missing first location in exported files 2010-06-06 23:31:03 +02:00
Rodrigo Damazio 88b2b85f2a Making Track and Waypoint use the TripStatisticsData class.
This grealy simplifies those classes since the fields are the same.
There's certainly more cleanup to do on top of this, but I thought this
was already more than enough for a single change.

The only *functional* change expected from this is that the average
speed is now calculated over the time until the last known position,
which IMHO makes sense since the distance used in that calculation only
includes up to that position. The visible effect is that having no GPS
signal doesn't make the speed decrease.

This was imported from perforce CL 15953263.
2010-06-04 14:59:09 -03:00
Rodrigo Damazio 2c1dff6ac8 Adding test project files (TODO: replace easymock with android mock) 2010-06-02 19:26:31 -03:00
Rodrigo Damazio 481b42f563 Auto-merge 2010-06-02 16:58:49 -03:00
Rodrigo Damazio 597c321009 Added tag v1.0.15 for changeset e774d13e5b6a 2010-06-02 16:57:46 -03:00
Rodrigo Damazio 76651f75d8 Automated merge with https://tnapierala-mytracks.googlecode.com/hg/ 2010-06-02 16:22:24 -03:00
t napierala 3d8bae55a1 pl_PL - removed some non-translatable strings 2010-06-01 10:00:28 +02:00
Steffen Horlacher 4b6869e367 Added check for negative time changes and bugfix for files with multiple tracks 2010-05-30 20:06:22 +02:00
Steffen Horlacher 477ba7c081 Changes according to comments 2010-05-30 18:10:56 +02:00
johan helin 5b6d9725b8 Removed all strings that should not be translated in the swedish translation of arrays.xml 2010-05-30 14:01:26 +02:00
t napierala 25c3cea115 pl_PL removed colors.xml, removed non-translatable strings as per Issue 68, comment 2 2010-05-30 13:20:08 +02:00
johan helin d90601276f Finnished translating my tracks to swedish 2010-05-29 13:30:20 +02:00
johan helin 4f692bc698 Finnished translating strings.xml and did some more of the strings in arrays.xml 2010-05-29 12:44:30 +02:00
johan helin d8dd02eef0 Further strings translated 2010-05-28 22:38:04 +02:00
johan helin 8ad65ae233 First commit with cleanup from english and some strings translated 2010-05-28 22:22:39 +02:00
t napierala eabbb4569b final translation 2010-05-26 16:34:26 +02:00
t napierala 49888b771d first part of changes 2010-05-26 14:29:40 +02:00
ob 2b1c1cd052 Add a missing string for "Elevation" to the French strings.xml file. 2010-05-24 18:23:39 +01:00
Steffen Horlacher 61884e67ec track rollback: javadoc and some minor other corrections 2010-05-23 12:58:50 +02:00
Steffen Horlacher 9a2f028843 code format 2010-05-23 11:26:41 +02:00
Steffen Horlacher 2b56acf164 code format 2010-05-23 11:21:27 +02:00
Steffen 98b67dcc28 Sax style GPX file importer and tests 2010-05-23 11:08:51 +02:00
Rodrigo Damazio 500dfa3107 Releasing mytracks 1.0.15 2010-05-23 00:00:00 -03:00
Rodrigo Damazio c4efcfd2db Fixing bug in GPX import - we were reading the last point time too soon 2010-05-22 01:17:59 -07:00
Rodrigo Damazio 81ee6bbcf6 Add a few calls back into SendToMyMaps which actually add the stats to the ending waypoint. (imported from perforce) 2010-05-22 00:41:40 -07:00
Rodrigo Damazio e4e2e76e06 Added tag v1.0.14 for changeset 4c02a4515632 2010-05-20 16:53:43 -07:00
Rodrigo Damazio f847862e84 Releasing 1.0.14 (no code changes, just a release mistake) 2010-05-20 16:53:40 -07:00
Rodrigo Damazio 427dbeafde Added tag v1.0.13 for changeset 84cce31f6b83 2010-05-20 12:18:35 -07:00
Rodrigo Damazio 99ac85b40e Releasing 1.0.13 2010-05-20 12:18:29 -07:00
Rodrigo Damazio 020388baed Fixing uploading bug which happened in gzipped responses 2010-05-20 11:21:46 -07:00
Rodrigo Damazio 4ade79de4f Added tag v1.0.12 for changeset 51aa4e7cf7d8 2010-05-20 05:14:00 -03:00
Rodrigo Damazio 870dda9b8b Importing tests source 2010-05-19 17:35:08 -07:00
Rodrigo Damazio 27dd5298f7 Importing all the source code :) 2010-05-19 17:32:31 -07:00
Rodrigo Damazio 6d5d406ce9 Importing external libraries 2010-05-19 17:31:41 -07:00
Rodrigo Damazio ffb5e7e6f7 Importing project files 2010-05-19 17:31:20 -07:00
Rodrigo Damazio 0de101c89f Updating resources to the latest version 2010-05-19 17:30:26 -07:00
Rodrigo Damazio bd3a0766e1 Adding service definition 2010-05-07 17:58:54 -03:00
Rodrigo Damazio f536cc8f8a Adding hgignore for bin and gen dirs 2010-05-07 15:59:52 -03:00
Rodrigo Damazio 826c0495fc Initial import of MyTracks content files and their dependencies.
MyTracksUtils and MyTracksConstants are cut-down versions of the original files
which contain only what's used by the content package, we'll later post the rest
of them.
2010-05-07 15:59:33 -03:00
Rodrigo Damazio 9eac541ce5 Initial import of MyTracks resources and assets 2010-05-07 15:57:42 -03:00
128 changed files with 2426 additions and 5148 deletions
-1
View File
@@ -5,4 +5,3 @@ syntax:glob
*/proguard/**
.metadata
MyTracksTest/annotations.log
MyTracks/src/com/google/android/apps/mytracks/io/mymaps
-1
View File
@@ -8,7 +8,6 @@
<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"/>
<classpathentry kind="lib" path="libs/libmymaps.jar"/>
<classpathentry kind="src" path="MyTracksLib_src"/>
<classpathentry kind="output" path="bin"/>
</classpath>
+5 -12
View File
@@ -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="26"
android:versionName="1.1.3">
android:versionCode="22"
android:versionName="1.0.21">
<application android:icon="@drawable/arrow_icon"
android:label="@string/app_name"
android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent">
@@ -56,11 +56,6 @@ limitations under the License.
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.MyTracksList"
android:label="Recorded Tracks" />
@@ -110,7 +105,7 @@ limitations under the License.
<!-- Permissions to initialize service -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- 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" />
@@ -127,7 +122,6 @@ limitations under the License.
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.fusiontables" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.local" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.wise" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.writely" />
@@ -164,15 +158,14 @@ limitations under the License.
<!-- Features required -->
<uses-feature android:name="android.hardware.location" android:required="true"/>
<uses-feature android:name="android.hardware.location.gps" android:required="true"/>
<uses-feature android:name="android.hardware.touchscreen" android:required="true"/>
<!-- Features optional -->
<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
<uses-feature android:name="android.hardware.faketouch" android:required="false"/>
<uses-feature android:name="android.hardware.location.network" android:required="false"/>
<uses-feature android:name="android.hardware.sensor.compass" android:required="false"/>
<uses-feature android:name="android.hardware.telephony" android:required="false"/>
<uses-feature android:name="android.hardware.telephony.gsm" android:required="false"/>
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false"/>
<uses-sdk android:minSdkVersion="3"/>
+1 -1
View File
@@ -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:9
android.library.reference.1=../MyTracksLib/
# ProGuard is turned off while we investigate the removal of code that
-17
View File
@@ -1,17 +0,0 @@
The libraries contained here in binary format are licensed according to their
own licenses, which allow their usage for the My Tracks application. Any other
applications that wish to use these files should consult the appropriate
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/
google-common.jar,
googleloginclient-helper.jar,
libmymaps.jar (Google My Maps upload library):
Licensed exclusively for use in My Tracks and derived Android applications.
Binary file not shown.
+1 -7
View File
@@ -15,17 +15,11 @@
-dontwarn org.codehaus.**
-dontwarn com.google.appengine.**
# Make our stack traces useful
# Line numbers will be correct, file names will be replaced by "MT" since the
# class name is enough to get the file name.
-renamesourcefileattribute MT
-keepattributes SourceFile,LineNumberTable
# Keep everything android references from XMLs
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.app.backup.BackupAgent
-keep public class * extends android.app,backup.BackupAgent
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.preference.Preference
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 676 B

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 384 B

After

Width:  |  Height:  |  Size: 384 B

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

-103
View File
@@ -1,103 +0,0 @@
<?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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apl/res/com.google.android.maps"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_bar"
android:layout_weight="0"
android:padding="3dip">
<TextView android:id="@+id/message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="16dip"
android:textColor="#fff"
android:text="@string/select_map_message"
android:layout_weight="0"/>
</LinearLayout>
<ListView android:id="@+id/maplist"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView android:id="@+id/mapslist_empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:gravity="center"
android:padding="3dip"
android:textSize="16dip"
android:textColor="#c00"
android:textStyle="bold"
android:text="@string/mapslist_no_maps_available"
android:visibility="gone"/>
<TextView android:id="@+id/failed"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="3dip"
android:textSize="16dip"
android:textColor="#c00"
android:textStyle="bold"
android:text="@string/maps_list_failed"
android:visibility="gone"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_bar"
android:layout_weight="0"
android:padding="3dip">
<LinearLayout android:id="@+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="3dip"
android:layout_gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<ProgressBar
android:layout_height="20dip"
android:layout_width="20dip"
android:layout_gravity="center"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="3dip"
android:textSize="16dip"
android:textColor="#fff"
android:textStyle="bold"
android:text="@string/maps_list_loading"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
</LinearLayout>
-6
View File
@@ -50,12 +50,6 @@ limitations under the License.
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button android:id="@+id/tracklist_btn_import_all"
android:layout_width="wrap_content"
android:layout_height="48dip"
android:layout_gravity="left|top"
android:text="@string/tracklist_btn_import_all"
android:textSize="14dip"/>
<Button android:id="@+id/tracklist_btn_export_all"
android:layout_width="wrap_content"
android:layout_height="48dip"
@@ -41,39 +41,6 @@ limitations under the License.
android:stretchColumns="1"
android:layout_marginTop="5dip"
android:layout_marginLeft="5dip">
<!-- My Maps -->
<TableRow>
<ImageView android:src="@drawable/mymaps_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="10dip">
<CheckBox android:id="@+id/sendtogoogle_google_mymaps"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/sendtogoogle_google_mymaps"
android:textSize="20dip"
android:checked="true"/>
<RadioGroup android:id="@+id/sendtogoogle_group_mymaps"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<RadioButton android:id="@+id/sendtogoogle_create_new_map"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/sendtogoogle_create_new_map"/>
<RadioButton android:id="@+id/sendtogoogle_pick_existing_map"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/sendtogoogle_pick_existing_map"/>
</RadioGroup>
</LinearLayout>
</TableRow>
<!-- Fusion Tables -->
<TableRow>
<ImageView android:src="@drawable/googledocs_icon"
android:layout_width="wrap_content"
@@ -91,8 +58,6 @@ limitations under the License.
android:checked="true"/>
</LinearLayout>
</TableRow>
<!-- Google Docs -->
<TableRow>
<ImageView android:src="@drawable/googledocs_icon"
android:layout_width="wrap_content"
@@ -1,65 +0,0 @@
<?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.
-->
<!--
This layout is used as the content view for the send-to-Google result dialog.
It is used to summarize the results of uploading track data to one or more
services.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:paddingLeft="14dip"
android:paddingRight="14dip"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/status_track_upload_status"
style="?android:attr/textAppearanceLarge"/>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<!-- We don't want a divider, so we set its color to transparent. -->
<!-- We do this explicitly, rather than with a color resource, because -->
<!-- an apparent bug causes the divider to be wildly misrendered on -->
<!-- a Mini X10 running 2.1. -->
<ListView
android:id="@+id/send_to_google_result_list"
android:clickable="false"
android:paddingTop="10dip"
android:paddingBottom="10dip"
android:divider="#00000000"/>
</TableLayout>
<TextView
android:id="@+id/send_to_google_result_comment"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/status_mymap_info"
android:visibility="gone"
style="?android:attr/textAppearanceSmall"/>
<TextView
android:id="@+id/send_to_google_result_error"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/error_please_try_again_later"
android:visibility="gone"
style="?android:attr/textAppearanceLarge"/>
</LinearLayout>
@@ -1,49 +0,0 @@
<?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.
-->
<!--
This layout represents the result of sending track data to a single service.
It will be instantiated by a custom ListAdapter - once for each service to
which track data was uploaded.
-->
<TableRow
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/send_to_google_result_icon"
android:src="@drawable/success"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_gravity="top"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/send_to_google_result_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Google Docs"
style="?android:attr/textAppearanceMedium"/>
<TextView
android:id="@+id/send_to_google_result_url"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="http://google.com"
style="?android:attr/textAppearanceSmall"/>
</LinearLayout>
</TableRow>
+9 -8
View File
@@ -54,7 +54,7 @@ limitations under the License.
<string name="status_tracks_have_been_uploaded">S\'ha enviat la ruta a maps.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_new_doc">S\'ha enviat la ruta a un full de càlcul a docs.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_docs">S\'ha enviat la ruta a docs.google.com.</string>
<string name="status_enable_gps">Toqueu aquí per anar als paràmetres de seguretat i ubicació i activeu \'habilita els satèl·lits GPS\'. Premeu el botó d\'anar enrere per tornar.</string>
<string name="status_enable_gps">Piqueu aquí per anar als paràmetres de seguretat i ubicació i activeu \'habilita els satèl·lits GPS\'. Premeu el botó d\'anar enrere per tornar.</string>
<string name="status_approximate_location">Nota: Es mostra una ubicació determinada a partir de les xarxes sense fils i antenes telefòniques.</string>
<string name="status_no_location">No es pot determinar la ubicació. Habiliteu més fonts d\'ubicació (vegeu els paràmetres de seguretat i ubicació) i assegureu-vos que el cel és visible. Proveu de nou més tard.</string>
<string name="status_waypoint_inserted">S\'ha inserit un marcader de punt de ruta.</string>
@@ -133,6 +133,7 @@ limitations under the License.
<string name="tracklist_all_tracks">Totes les rutes:</string>
<string name="tracklist_this_track">Aquesta ruta</string>
<string name="tracklist_share_track">Comparteix amb amics...</string>
<string name="tracklist_share_linkfusion">Un enllaç a Google Fusion Table</string>
<string name="tracklist_share_gpx_file">Un fitxer GPX</string>
<string name="tracklist_share_kml_file">Un fitxer KML</string>
<string name="tracklist_share_csv_file">Un fitxer CSV</string>
@@ -170,7 +171,7 @@ limitations under the License.
<string name="settings_not_available_summary">No es troba disponible a la vostra versió de l\'Android</string>
<string name="settings_announcement_frequency">Freqüència d\'avís</string>
<string name="settings_announcement_frequency_summary">Temps mínim entre dos avisos de veu</string>
<string name="settings_announcement_frequency_summary">Temps mínin entre dos avisos de veu</string>
<string name="settings_min_recording_distance">Distància mínima entre punts</string>
<string name="settings_min_recording_distance_summary">La distància més petita entre dos punts enregistrats de la vostra posició</string>
@@ -181,7 +182,7 @@ limitations under the License.
<string name="settings_min_recording_interval">Temps mínim entre punts</string>
<string name="settings_min_recording_interval_summary">Interval de temps mínim entre dos enregistraments de la vostra posició</string>
<string name="settings_min_required_accuracy">Precisió mínima</string>
<string name="settings_min_required_accuracy">Precisió míima</string>
<string name="settings_min_required_accuracy_summary">S\'aturarà l\'enregistrament si la vostra posició no és així de precisa com a mínim</string>
<string name="settings_metric_units">Fes servir unitats mètriques</string>
@@ -239,13 +240,13 @@ limitations under the License.
<!-- Sharing -->
<string name="share_map_subject">M\'agradaria compartir un mapa amb tu</string>
<string name="share_map_body_format">Em sembla que estaràs interessat en aquest mapa:
<string name="share_map_body_format">Crec que estaràs interessat en aquest mapa:
%s</string>
<string name="send_track_subject">M\'agradaria compartir una ruta amb tu</string>
<string name="send_track_body_format">Em sembla que estaràs interessat en aquesta ruta.
<string name="send_track_body_format">Crec que estaràs interessat en aquesta ruta.
Per veure aquesta ruta fes servir Google Earth o altre programari de mapes.</string>
Per verue aquesta ruta fes servir Google Earth o altre programari de mapes.</string>
<string name="share_track">Comparteix la ruta amb amics</string>
<!-- Visibility -->
@@ -255,8 +256,8 @@ limitations under the License.
<!-- Statistics View -->
<!-- Average Moving -->
<string name="average_moving_speed_label">Velocitat mitjana en moviment</string>
<string name="average_moving_pace_label">Ritme mitjà en moviment</string>
<string name="average_moving_speed_label">Average Moving Speed</string>
<string name="average_moving_pace_label">Average Moving Pace</string>
<!-- Average -->
<string name="average_speed_label">Velocitat mitjana</string>
+306 -331
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2010 Google Inc.
@@ -13,244 +13,240 @@ 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">Track aufzeichnen</string>
<string name="stop_recording">Aufzeichnung anhalten</string>
<string name="switch_to_sat">Satellitenansicht</string>
<string name="switch_to_map">Kartenansicht</string>
<string name="mylocation">Mein Aufenthaltsort</string>
<!--string name="list_tracks">Tracks</string-->
-->
<resources>
<!-- Used by the Menu -->
<string name="start_recording">Track aufzeichnen</string>
<string name="stop_recording">Aufzeichnung anhalten</string>
<string name="switch_to_sat">Satellitenansicht</string>
<string name="switch_to_map">Kartenansicht</string>
<string name="mylocation">Mein Aufenthaltsort</string>
<string name="list_markers">Wegpunkte</string>
<string name="delete_all_tracks">Alle Tracks löschen</string>
<string name="settings">Einstellungen</string>
<string name="elevation">Höhe</string>
<string name="choose_track_message">Bitte wähle einen Track zur Ansicht aus</string>
<string name="current_track">Aktueller Track</string>
<string name="current_segment">Letztes Segment</string>
<string name="sensor_state">Sensorstatus</string>
<string name="aggregated_stats">Aggregierte Statistiken</string>
<string name="delete_all_tracks">Alle Tracks löschen</string>
<string name="settings">Einstellungen</string>
<string name="elevation">Höhe</string>
<string name="choose_track_message">Bitte wähle einen Track zur Ansicht aus</string>
<string name="current_track">Aktueller Track</string>
<string name="current_segment">Letztes Segment</string>
<string name="sensor_state">Sensorstatus</string>
<string name="aggregated_stats">Aggregierte Statistiken</string>
<!-- Error messages -->
<string name="error_no_location_manager">Es wurde kein Dienst zur Positionsermittlung auf diesem Gerät gefunden.</string>
<string name="error_no_gps_location_provider">Es wurde kein GPS-Empfänger auf diesem Gerät gefunden.</string>
<string name="error_sending_to_fusiontables">Beim Senden des Tracks an Google Fusion Tables ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.</string>
<string name="error_sending_to_docs">Beim Senden des Tracks an Google Text &amp; Tabellen ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.</string>
<string name="error_unable_to_start_recording">Start der Aufzeichnung fehlgeschlagen. Bitte versuche es noch einmal.</string>
<string name="error_unable_to_stop_recording">Anhalten unmöglich. Bitte versuche es noch einmal.</string>
<string name="error_unable_to_read_file">Konnte Datei nicht lesen.</string>
<string name="error_invalid_gpx_format">Datei ist nicht im GPX-Format.</string>
<string name="error_generic">Ein Fehler ist aufgetreten. Bitte versuche es noch einmal.</string>
<string name="error_track_does_not_exist">Track existiert nicht.</string>
<string name="error_out_of_memory">Die Datei ist zu groß (maximal 500 KB). Operation abgebrochen.</string>
<string name="error_unable_to_insert_marker">Der Wegpunkt kann nicht einfügt werden. Keine Positionsbestimmung möglich.</string>
<!-- Error messages -->
<string name="error_no_location_manager">Es wurde kein Dienst zur Positionsermittlung auf diesem Gerät gefunden.</string>
<string name="error_no_gps_location_provider">Es wurde kein GPS-Empfänger auf diesem Gerät gefunden.</string>
<string name="error_sending_to_fusiontables">Beim Senden des Tracks an Google Fusion Tables ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.</string>
<string name="error_sending_to_docs">Beim Senden des Tracks an Google Docs ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.</string>
<string name="error_unable_to_start_recording">Start der Aufzeichnung fehlgeschlagen. Bitte versuche es noch einmal.</string>
<string name="error_unable_to_stop_recording">Anhalten unmöglich. Bitte versuche es noch einmal.</string>
<string name="error_unable_to_read_file">Konnte Datei nicht lesen.</string>
<string name="error_invalid_gpx_format">Datei ist nicht im GPX-Format.</string>
<string name="error_generic">Ein Fehler ist aufgetreten. Bitte versuche es noch einmal.</string>
<string name="error_track_does_not_exist">Track existiert nicht.</string>
<string name="error_out_of_memory">Die Datei ist zu groß (maximal 500 KB). Operation abgebrochen.</string>
<string name="error_unable_to_insert_marker">Der Wegpunkt kann nicht einfügt werden. Keine Positionsbestimmung möglich.</string>
<!-- Status messages -->
<string name="wait_for_fix">Warte auf ein besseres GPS-Signal. Bitte stelle sicher, dass der Himmel sichtbar ist.</string>
<string name="status_now_recording">Ein neuer Track wird aufgezeichnet.</string>
<string name="status_stopped_recording">Die Aufzeichnung wurde angehalten.</string>
<string name="status_new_fusiontable_has_been_created">Eine neue Tabelle wurde auf google.com/fusiontables erstellt.</string>
<string name="status_tracks_have_been_uploaded">Dein Track wurde auf maps.google.com gespeichert.</string>
<string name="status_tracks_have_been_uploaded_to_new_doc">Dein Track wurde in einer neuen Tabelle bei docs.google.com gespeichert.</string>
<string name="status_tracks_have_been_uploaded_to_docs">Dein Track wurde an docs.google.com gesendet.</string>
<string name="status_enable_gps">Hier berühren, um zu den Sicherheits- und Positionseinstellungen zu gelangen. Aktiviere \'GPS-Satelliten\'. Drücke dann den Zurück-Knopf, um hierher zurückzukehren.</string>
<string name="status_approximate_location">Anmerkung: Eine ungefähre Position wird angezeigt, bestimmt mittels Mobilfunkstationen und WiFi-Netzwerken.</string>
<string name="status_no_location">Die Position kann derzeit nicht bestimmt werden. Aktiviere mehr Positionsquellen (siehe Sicherheits- und Positionseinstellungen) und stelle sicher, dass der Himmel sichtbar ist.</string>
<string name="status_waypoint_inserted">Ein Wegpunkt wurde eingefügt.</string>
<string name="status_statistics_inserted">Ein Statistikwegpunkt wurde eingefügt.</string>
<!-- Status messages -->
<string name="wait_for_fix">Warte auf ein besseres GPS-Signal. Bitte stelle sicher, dass der Himmel sichtbar ist.</string>
<string name="status_now_recording">Ein neuer Track wird aufgezeichnet.</string>
<string name="status_stopped_recording">Die Aufzeichnung wurde angehalten.</string>
<string name="status_new_fusiontable_has_been_created">Eine neue Tabelle wurde auf google.com/fusiontables erstellt.</string>
<string name="status_tracks_have_been_uploaded">Dein Track wurde auf maps.google.com gespeichert.</string>
<string name="status_tracks_have_been_uploaded_to_new_doc">Dein Track wurde in einer neuen Tabelle bei docs.google.com gespeichert.</string>
<string name="status_tracks_have_been_uploaded_to_docs">Dein Track wurde an docs.google.com gesendet.</string>
<string name="status_enable_gps">Hier berühren, um zu den Sicherheits- und Positionseinstellungen zu gelangen. Aktiviere \'GPS-Satelliten\'. Drücke dann den Zurück-Knopf, um hierher zurückzukehren.</string>
<string name="status_approximate_location">Anmerkung: Eine ungefähre Position wird angezeigt, bestimmt mittels Mobilfunkstationen und WiFi-Netzwerken.</string>
<string name="status_no_location">Die Position kann derzeit nicht bestimmt werden. Aktiviere mehr Positionsquellen (siehe Sicherheits- und Positionseinstellungen) und stelle sicher, dass der Himmel sichtbar ist.</string>
<string name="status_waypoint_inserted">Ein Wegpunkt wurde eingefügt.</string>
<string name="status_statistics_inserted">Ein Statistikwegpunkt wurde eingefügt.</string>
<!-- Progress dialog -->
<string name="progress_title">Bitte warten…</string>
<string name="progress_message">Dein Track wird an Google gesendet...</string>
<string name="progress_message_reading_track">Lese Track...</string>
<string name="progress_message_preparing_track">Bereite Track vor...</string>
<string name="progress_message_authenticating_fusiontables">Anmeldung bei Google Fusion Tables...</string>
<string name="progress_message_authenticating_docs">Anmeldung bei Google Text &amp; Tabellen...</string>
<string name="progress_message_sending_docs">Track wird an Google Text &amp; Tabellen gesendet...</string>
<string name="progress_message_sending_fusiontables">Track wird an Google Fusion Tables gesendet...</string>
<string name="progress_message_creating_fusiontable">Neue \'Fusion Tabelle\' wird erstellt...</string>
<string name="import_progress_message">Importiere GPS-Track. Das kann ein wenig dauern.</string>
<string name="write_progress_message">Schreibe Datei auf SD-Karte. Das kann ein wenig dauern.</string>
<string name="progress_message_updating_track">Aktualisiere Trackstatistik...</string>
<!-- Progress dialog -->
<string name="progress_title">Bitte warten…</string>
<string name="progress_message">Dein Track wird an Google gesendet...</string>
<string name="progress_message_reading_track">Lese Track...</string>
<string name="progress_message_preparing_track">Bereite Track vor...</string>
<string name="progress_message_authenticating_fusiontables">Anmeldung bei Google Fusion Tables...</string>
<string name="progress_message_authenticating_docs">Anmeldung bei Google Docs...</string>
<string name="progress_message_sending_docs">Track wird an Google Docs gesendet...</string>
<string name="progress_message_sending_fusiontables">Track wird an Google Fusion Tables gesendet...</string>
<string name="progress_message_creating_fusiontable">Neue \'Fusion Tabelle\' wird erstellt...</string>
<string name="import_progress_message">Importiere GPS-Track. Das kann ein wenig dauern.</string>
<string name="write_progress_message">Schreibe Datei auf SD-Karte. Das kann ein wenig dauern.</string>
<string name="progress_message_updating_track">Aktualisiere Trackstatistik...</string>
<!-- Used by DeleteAllDataHandler -->
<string name="are_you_sure_question">Bist Du Dir wirklich sicher?</string>
<string name="all_data_will_be_permanently_deleted">Alle Tracks und Wegpunkte werden endgültig von diesem Gerät gelöscht.</string>
<string name="track_will_be_permanently_deleted">Dieser Track und seine Wegpunkte werden endgültig von diesem Gerät gelöscht.</string>
<string name="marker_will_be_permanently_deleted">Dieser Wegpunkt wird endgültig von diesem Gerät gelöscht.</string>
<!-- Used by DeleteAllDataHandler -->
<string name="are_you_sure_question">Bist Du Dir wirklich sicher?</string>
<string name="all_data_will_be_permanently_deleted">Alle Tracks und Wegpunkte werden endgültig von diesem Gerät gelöscht.</string>
<string name="track_will_be_permanently_deleted">Dieser Track und seine Wegpunkte werden endgültig von diesem Gerät gelöscht.</string>
<string name="marker_will_be_permanently_deleted">Dieser Wegpunkt wird endgültig von diesem Gerät gelöscht.</string>
<!-- Text and links when uploading to Google Fusion Tables -->
<string name="new_map_description">Erstellt von My Tracks für Android.</string>
<!-- Text and links when uploading to Google Fusion Tables -->
<string name="new_map_description">Erstellt von My Tracks für Android.</string>
<string name="fusiontable_link">Erstellt von &lt;a href=\'http://mytracks.appspot.com\'&gt;My Tracks&lt;/a&gt; für Android.</string>
<!-- Formatting of track and marker descriptions -->
<string name="points">Punkte</string>
<string name="recorded_date">Aufgezeichnet am</string>
<string name="category">Aktivität</string>
<string name="waypoint_category">Art des Wegpunktes</string>
<string name="part">(Teil %d)</string>
<!-- Formatting of track and marker descriptions -->
<string name="points">Punkte</string>
<string name="recorded_date">Aufgezeichnet am</string>
<string name="category">Aktivität</string>
<string name="waypoint_category">Art des Wegpunktes</string>
<string name="part">(Teil %d)</string>
<!-- Used by the track recording service -->
<!-- Used by the track recording service -->
<string name="recording_your_track">Dein Track wird aufgezeichnet…</string>
<!--string name="new_track">Track %d</string-->
<!-- Common -->
<string name="no">Nein</string>
<string name="yes">Ja</string>
<!--string name="ok">OK</string-->
<string name="error">Fehler</string>
<string name="success">Erfolgreich</string>
<string name="waypoint">Wegpunkt</string>
<!-- Common -->
<string name="no">Nein</string>
<string name="yes">Ja</string>
<string name="error">Fehler</string>
<string name="success">Erfolgreich</string>
<string name="waypoint">Wegpunkt</string>
<string name="license">Lizenz</string>
<string name="cancel">Abbrechen</string>
<string name="close">Schließen</string>
<string name="edit">Bearbeiten</string>
<string name="save">Sichern</string>
<!-- Placemark labels for start and end of track -->
<!--string name="start">(Start)</string-->
<string name="end">(Ende)</string>
<!-- Placemark labels for start and end of track -->
<string name="end">(Ende)</string>
<!-- TrackList -->
<string name="tracklist_show_track">Anzeigen</string>
<!-- TrackList -->
<string name="tracklist_show_track">Anzeigen</string>
<string name="tracklist_send_to_fusiontables">An eine Google Fusion Tables-Karte senden</string>
<string name="tracklist_send_to_new_fusiontable">An eine neue Google Fusion Tables-Karte senden</string>
<string name="tracklist_send_to_docs">An Google Text &amp; Tabellen senden</string>
<string name="tracklist_send_to_google">An Google senden…</string>
<string name="tracklist_delete_track">Vom Gerät löschen…</string>
<string name="tracklist_edit_track">Bearbeiten</string>
<string name="tracklist_write_to_sd">Auf SD-Karte speichern…</string>
<string name="tracklist_save_as_gpx">GPX-Datei exportieren</string>
<string name="tracklist_save_as_kml">KML-Datei exportieren</string>
<string name="tracklist_save_as_csv">CSV-Datei exportieren</string>
<string name="tracklist_save_as_tcx">TCX-Datei exportieren</string>
<string name="tracklist_btn_send_all_to_fusiontables">An Google Fusion Tables senden</string>
<string name="tracklist_btn_delete_all">Alle Tracks löschen</string>
<string name="tracklist_send_to_new_fusiontable">An eine neue Google Fusion Tables-Karte senden</string>
<string name="tracklist_send_to_docs">An Google Docs senden</string>
<string name="tracklist_send_to_google">An Google senden…</string>
<string name="tracklist_delete_track">Vom Gerät löschen…</string>
<string name="tracklist_edit_track">Bearbeiten</string>
<string name="tracklist_write_to_sd">Auf SD-Karte speichern…</string>
<string name="tracklist_save_as_gpx">GPX-Datei exportieren</string>
<string name="tracklist_save_as_kml">KML-Datei exportieren</string>
<string name="tracklist_save_as_csv">CSV-Datei exportieren</string>
<string name="tracklist_save_as_tcx">TCX-Datei exportieren</string>
<string name="tracklist_btn_send_all_to_fusiontables">An Google Fusion Tables senden</string>
<string name="tracklist_btn_delete_all">Alle Tracks löschen</string>
<!-- Export All -->
<string name="tracklist_btn_export_all">Alle Tracks exportieren</string>
<string name="export_done">Exportieren beendet</string>
<string name="tracklist_pick_one">Einen Track auswählen. Lange berühren für mehr Optionen.</string>
<string name="tracklist_all_tracks">Alle Tracks</string>
<string name="tracklist_this_track">Dieser Track</string>
<string name="tracklist_share_track">Mit Freunden teilen…</string>
<string name="tracklist_share_linkfusion">Ein Link zur Google Fusion Tables-Karte</string>
<string name="tracklist_share_gpx_file">Eine GPX-Datei</string>
<string name="tracklist_share_kml_file">Eine KML-Datei</string>
<string name="tracklist_share_csv_file">Eine CSV-Datei</string>
<string name="tracklist_share_tcx_file">Eine TCX-Datei</string>
<string name="tracklist_clear_map">Karte zurücksetzen.</string>
<string name="tracklist_btn_export_all">Alle Tracks exportieren</string>
<string name="export_done">Exportieren beendet</string>
<string name="tracklist_pick_one">Einen Track auswählen. Lange berühren für mehr Optionen.</string>
<string name="tracklist_all_tracks">Alle Tracks</string>
<string name="tracklist_this_track">Dieser Track</string>
<string name="tracklist_share_track">Mit Freunden teilen…</string>
<string name="tracklist_share_linkfusion">Ein Link zur Google Fusion Tables-Karte</string>
<string name="tracklist_share_gpx_file">Eine GPX-Datei</string>
<string name="tracklist_share_kml_file">Eine KML-Datei</string>
<string name="tracklist_share_csv_file">Eine CSV-Datei</string>
<string name="tracklist_share_tcx_file">Eine TCX-Datei</string>
<string name="tracklist_clear_map">Karte zurücksetzen.</string>
<!-- Waypoints list -->
<string name="waypointslist_btn_delete_all">Alle Wegpunkte löschen</string>
<string name="waypointslist_this_waypoint">Dieser Wegpunkt</string>
<string name="waypointslist_delete_waypoint">Löschen</string>
<string name="waypointslist_edit_waypoint">Details bearbeiten</string>
<string name="waypointslist_show_waypoint">Auf der Karte zeigen</string>
<string name="waypointslist_btn_insert_waypoint">Wegpunkt einfügen</string>
<string name="waypointslist_btn_insert_statistics">Statistik einfügen</string>
<string name="waypointslist_pick_one">Wegpunkt auswählen. Lange berühren für mehr Optionen.</string>
<!-- Waypoints list -->
<string name="waypointslist_btn_delete_all">Alle Wegpunkte löschen</string>
<string name="waypointslist_this_waypoint">Dieser Wegpunkt</string>
<string name="waypointslist_delete_waypoint">Löschen</string>
<string name="waypointslist_edit_waypoint">Details bearbeiten</string>
<string name="waypointslist_show_waypoint">Auf der Karte zeigen</string>
<string name="waypointslist_btn_insert_waypoint">Wegpunkt einfügen</string>
<string name="waypointslist_btn_insert_statistics">Statistik einfügen</string>
<string name="waypointslist_pick_one">Wegpunkt auswählen. Lange berühren für mehr Optionen.</string>
<!-- MyTracks Details -->
<string name="trackdetails_title">Trackdetails</string>
<string name="trackdetails_name">Name</string>
<string name="trackdetails_description">Beschreibung</string>
<string name="trackdetails_category">Aktivität (z. B. Wandern, Fahrradfahren, Laufen, Klettern…)</string>
<!-- MyTracks Details -->
<string name="trackdetails_title">Trackdetails</string>
<string name="trackdetails_name">Name</string>
<string name="trackdetails_description">Beschreibung</string>
<string name="trackdetails_category">Aktivität (z. B. Wandern, Fahrradfahren, Laufen, Klettern…)</string>
<!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Wegpunktdetails</string>
<string name="waypointdetails_name">Wegpunktname</string>
<string name="waypointdetails_description">Wegpunktbeschreibung</string>
<string name="waypointdetails_category">Art des Wegpunktes (z. B. Gebäude, Schlagloch, Sehenswürdigkeit…)</string>
<!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Wegpunktdetails</string>
<string name="waypointdetails_name">Wegpunktname</string>
<string name="waypointdetails_description">Wegpunktbeschreibung</string>
<string name="waypointdetails_category">Art des Wegpunktes (z. B. Gebäude, Schlagloch, Sehenswürdigkeit…)</string>
<!-- MyTracks Settings -->
<string name="mytracks_settings">Einstellungen für My Tracks</string>
<string name="settings_display">Anzeige</string>
<string name="settings_recording">Aufzeichnung</string>
<string name="settings_sharing">Mit Freunden teilen</string>
<!-- MyTracks Settings -->
<string name="mytracks_settings">Einstellungen für My Tracks</string>
<string name="settings_display">Anzeige</string>
<string name="settings_recording">Aufzeichnung</string>
<string name="settings_sharing">Mit Freunden teilen</string>
<string name="settings_not_available_summary">In dieser Android-Version nicht verfügbar</string>
<string name="settings_not_available_summary">In dieser Android-Version nicht verfügbar</string>
<string name="settings_announcement_frequency">Dauer zwischen Ansagen</string>
<string name="settings_announcement_frequency_summary">Kürzeste Zeit zwischen zwei Ansagen</string>
<string name="settings_announcement_frequency">Dauer zwischen Ansagen</string>
<string name="settings_announcement_frequency_summary">Kürzeste Zeit zwischen zwei Ansagen</string>
<string name="settings_min_recording_distance">Kleinste Entfernung zwischen Punkten</string>
<string name="settings_min_recording_distance_summary">Kleinste Entfernung zwischen zwei Positionsaufzeichnungen</string>
<string name="settings_min_recording_distance">Kleinste Entfernung zwischen Punkten</string>
<string name="settings_min_recording_distance_summary">Kleinste Entfernung zwischen zwei Positionsaufzeichnungen</string>
<string name="settings_max_recording_distance">Neues Segment, wenn Punkte weiter entfernt als</string>
<string name="settings_max_recording_distance_summary">Der Track wird in zwei geteilt, wenn zwei folgende Punkte weiter entfernt sind als hier angegeben.</string>
<string name="settings_max_recording_distance">Neues Segment, wenn Punkte weiter entfernt als</string>
<string name="settings_max_recording_distance_summary">Der Track wird in zwei geteilt, wenn zwei folgende Punkte weiter entfernt sind als hier angegeben.</string>
<string name="settings_min_recording_interval">Aufzeichnungsfrequenz</string>
<string name="settings_min_recording_interval_summary">Kürzeste Zeit zwischen zwei Positionsaufzeichnungen</string>
<string name="settings_min_recording_interval">Aufzeichnungsfrequenz</string>
<string name="settings_min_recording_interval_summary">Kürzeste Zeit zwischen zwei Positionsaufzeichnungen</string>
<string name="settings_min_required_accuracy">Aufzeichnung pausieren, wenn Genauigkeit kleiner als</string>
<string name="settings_min_required_accuracy_summary">Die Aufzeichnung wird kurzfristig angehalten, wenn Deine Position nicht genauer als hier angegeben ermittelt werden kann.</string>
<string name="settings_min_required_accuracy">Aufzeichnung pausieren, wenn Genauigkeit kleiner als</string>
<string name="settings_min_required_accuracy_summary">Die Aufzeichnung wird kurzfristig angehalten, wenn Deine Position nicht genauer als hier angegeben ermittelt werden kann.</string>
<string name="settings_metric_units">Entfernungen in metrischen Einheiten anzeigen</string>
<string name="settings_metric_units_summary_on">Alle Entfernungen werden in metrischen Einheiten angezeigt.</string>
<string name="settings_metric_units_summary_off">Alle Entfernungen werden in imperialen Längeneinheiten angezeigt.</string>
<string name="settings_metric_units">Entfernungen in metrischen Einheiten anzeigen</string>
<string name="settings_metric_units_summary_on">Alle Entfernungen werden in metrischen Einheiten angezeigt.</string>
<string name="settings_metric_units_summary_off">Alle Entfernungen werden in imperialen Längeneinheiten angezeigt.</string>
<string name="settings_map_public">Karten auf maps.google.com veröffentlichen</string>
<string name="settings_map_public_summary_on">Hochgeladene Karten auf maps.google.com sind für alle sichtbar.</string>
<string name="settings_map_public_summary_off">Hochgeladene Karten auf maps.google.com werden nicht öffentlich sichtbar aufgelistet.</string>
<string name="settings_map_public">Karten auf maps.google.com veröffentlichen</string>
<string name="settings_map_public_summary_on">Hochgeladene Karten auf maps.google.com sind für alle sichtbar.</string>
<string name="settings_map_public_summary_off">Hochgeladene Karten auf maps.google.com werden nicht öffentlich sichtbar aufgelistet.</string>
<string name="settings_report_speed_or_pace">Geschwindigkeitsanzeige</string>
<string name="settings_report_speed_or_pace_summary_on">Geschwindigkeit wird angezeigt.</string>
<string name="settings_report_speed_or_pace_summary_off">Pace wird angezeigt.</string>
<string name="settings_report_speed_or_pace">Geschwindigkeitsanzeige</string>
<string name="settings_report_speed_or_pace_summary_on">Geschwindigkeit wird angezeigt.</string>
<string name="settings_report_speed_or_pace_summary_off">Pace wird angezeigt.</string>
<string name="settings_share_url_only">Nur URL als Einladung zum Teilen senden</string>
<string name="settings_share_url_only_summary_on">Beim Teilen mit Freunden wird nur die Karten-URL gesendet.</string>
<string name="settings_share_url_only_summary_off">Beim Teilen mit Freunden wird der GPS-Track selbst gesendet.</string>
<string name="settings_share_url_only">Nur URL als Einladung zum Teilen senden</string>
<string name="settings_share_url_only_summary_on">Beim Teilen mit Freunden wird nur die Karten-URL gesendet.</string>
<string name="settings_share_url_only_summary_off">Beim Teilen mit Freunden wird der GPS-Track selbst gesendet.</string>
<string name="settings_split_frequency">Zerteilungsfrequenz</string>
<string name="settings_split_frequency_summary">Längste Dauer oder Entfernung, nach der automatisch ein Marker eingefügt wird.</string>
<string name="settings_split_frequency">Zerteilungsfrequenz</string>
<string name="settings_split_frequency_summary">Längste Dauer oder Entfernung, nach der automatisch ein Marker eingefügt wird.</string>
<string name="settings_auto_resume_track_timeout">Zeitbegrenzung der Auto-Wiederaufnahme</string>
<string name="settings_auto_resume_track_timeout_summary">Maximale Zeit in Minuten, nach der eine abgebrochene Aufzeichnung nach einem Telefonneustart wiederaufgenommen wird.</string>
<string name="settings_auto_resume_track_timeout">Zeitbegrenzung der Auto-Wiederaufnahme</string>
<string name="settings_auto_resume_track_timeout_summary">Maximale Zeit in Minuten, nach der eine abgebrochene Aufzeichnung nach einem Telefonneustart wiederaufgenommen wird.</string>
<string name="settings_timestamp_track_name">Zeitstempel als Trackname</string>
<string name="settings_timestamp_track_name_summary_on">Der Trackname wird aus Datum und Zeit zum Aufzeichnungsbeginn zusammengesetzt.</string>
<string name="settings_timestamp_track_name_summary_off">Tracknamen erhalten eine fortlaufende Nummer.</string>
<string name="settings_timestamp_track_name">Zeitstempel als Trackname</string>
<string name="settings_timestamp_track_name_summary_on">Der Trackname wird aus Datum und Zeit zum Aufzeichnungsbeginn zusammengesetzt.</string>
<string name="settings_timestamp_track_name_summary_off">Tracknamen erhalten eine fortlaufende Nummer.</string>
<string name="pace_label">Pace</string>
<string name="pace_label">Pace</string>
<string name="eclair_required">Wird nur unter Android 2.0 oder höher unterstützt</string>
<string name="settings_sensor_type">Sensortyp</string>
<string name="eclair_required">Wird nur unter Android 2.0 oder höher unterstützt</string>
<string name="settings_sensor_type">Sensortyp</string>
<string name="settings_sensor_type_summary">Der Typ des zu verbindenden Sensors</string>
<string name="settings_heart_rate_ant_sensor_id">Verbindung mit ANT Herzqrequenzmesser aufheben</string>
<string name="settings_power_ant_sensor_id">Verbindung mit ANT Kraftmesser aufheben</string>
<string name="settings_srm_bridge_ant_sensor_id">Verbindung mit ANT srm bridge aufheben</string>
<string name="settings_ant_not_paired">ANT-Sensor nicht verbunden</string>
<string name="settings_ant_paired">ANT-Sensor verbunden mit: %d</string>
<string name="bluetooth_sensor_title">Bluetooth-Sensor</string>
<string name="bluetooth_sensor_summary">Der zu verbindende Bluetoothsensor</string>
<string name="settings_modular_stats_display_title">Art der Datenanzeige</string>
<string name="bluetooth_sensor_title">Bluetooth-Sensor</string>
<string name="bluetooth_sensor_summary">Der zu verbindende Bluetoothsensor</string>
<string name="settings_modular_stats_display_title">Art der Datenanzeige</string>
<!-- Backups -->
<string name="settings_backup">Datensicherung (BETA)</string>
<string name="settings_sd_backup">SD-Karten-Sicherung</string>
<string name="settings_backup_to_sd">Jetzt sichern</string>
<string name="settings_backup_to_sd_summary">Eine Kopie aller Deiner Tracks und Einstellungen auf die SD-Karte schreiben</string>
<string name="settings_restore_from_sd">Jetzt wiederherstellen</string>
<string name="settings_restore_from_sd_summary">Alle Tracks und Einstellungen von der SD-Karte holen.</string>
<string name="settings_no_backup_while_recording">Während ein Track aufgezeichnet wird, kann nicht mit der Datensicherung gearbeitet werden.</string>
<!-- Backups -->
<string name="settings_backup">Datensicherung (BETA)</string>
<string name="settings_sd_backup">SD-Karten-Sicherung</string>
<string name="settings_backup_to_sd">Jetzt sichern</string>
<string name="settings_backup_to_sd_summary">Eine Kopie aller Deiner Tracks und Einstellungen auf die SD-Karte schreiben</string>
<string name="settings_restore_from_sd">Jetzt wiederherstellen</string>
<string name="settings_restore_from_sd_summary">Alle Tracks und Einstellungen von der SD-Karte holen.</string>
<string name="settings_no_backup_while_recording">Während ein Track aufgezeichnet wird, kann nicht mit der Datensicherung gearbeitet werden.</string>
<string name="restore_overwrites_warning">Eine Wiederherstellung von der SD-Karte ÜBERSCHREIBT alle vorhandenen Tracks und Einstellungen. Willst Du das wirklich?</string>
<string name="select_backup_to_restore">Wähle die wiederherzustellende Datensicherung aus</string>
<string name="no_backups">Keine Datensicherungen gefunden.</string>
<string name="backup_write_progress_message">Schreibe alle Tracks und Einstellungen auf die SD-Karte. Dies kann eine Weile dauern...</string>
<string name="backup_import_progress_message">Lese alle Tracks und Einstellungen von der SD-Karte. Dies kann eine Weile dauern...</string>
<string name="restore_overwrites_warning">Eine Wiederherstellung von der SD-Karte ÜBERSCHREIBT alle vorhandenen Tracks und Einstellungen. Willst Du das wirklich?</string>
<string name="select_backup_to_restore">Wähle die wiederherzustellende Datensicherung aus</string>
<string name="no_backups">Keine Datensicherungen gefunden.</string>
<string name="backup_write_progress_message">Schreibe alle Tracks und Einstellungen auf die SD-Karte. Dies kann eine Weile dauern...</string>
<string name="backup_import_progress_message">Lese alle Tracks und Einstellungen von der SD-Karte. Dies kann eine Weile dauern...</string>
<!-- MyTracksSky -->
<string name="mytracks_sky">GPS-Satelliten</string>
<!-- MyTracksSky -->
<string name="mytracks_sky">GPS-Satelliten</string>
<!-- Sharing -->
<!-- Sharing -->
<string name="share_map">Karte mit Freunden teilen</string>
<string name="share_map_subject">Ich möchte gerne eine Karte mit Dir teilen.</string>
<string name="share_map_subject">Ich möchte gerne eine Karte mit Dir teilen.</string>
<string name="share_map_body_format">Vielleicht interessierst Du Dich für diese Karte:
%s</string>
<string name="send_track_subject">Ich möchte einen GPS-Track mit Dir teilen</string>
%s</string>
<string name="send_track_subject">Ich möchte einen GPS-Track mit Dir teilen</string>
<string name="send_track_body_format">Vielleicht interessierst Du Dich für diese Track:
%s.</string>
@@ -261,145 +257,126 @@ limitations under the License.
<string name="unlisted_map">Nicht in Suchergebnissen enthalten.</string>
<string name="mapslist_no_maps_available">Du hast noch keine Karten.</string>
<!-- Statistics View -->
<!-- Average Moving -->
<string name="average_moving_speed_label">Durchschnitt in Bew.</string>
<string name="average_moving_pace_label">Pace in Bew.</string>
<!-- Statistics View -->
<!-- Average Moving -->
<string name="average_moving_speed_label">Durchschnitt in Bew.</string>
<string name="average_moving_pace_label">Pace in Bew.</string>
<!-- Average -->
<string name="average_speed_label">Durchschnittsgeschw.</string>
<string name="average_pace_label">Durchschnitts-Pace</string>
<!-- Average -->
<string name="average_speed_label">Durchschnittsgeschw.</string>
<string name="average_pace_label">Durchschnitts-Pace</string>
<string name="elevation_chart_name">Höhenprofil</string>
<string name="elevation_gain_label">Höhengewinn</string>
<string name="elevation_label">Höhe</string>
<string name="latitude_label">Breitengrad</string>
<string name="longitude_label">Längengrad</string>
<string name="elevation_chart_name">Höhenprofil</string>
<string name="elevation_gain_label">Höhengewinn</string>
<string name="elevation_label">Höhe</string>
<string name="latitude_label">Breitengrad</string>
<string name="longitude_label">Längengrad</string>
<!-- Min -->
<string name="min_elevation_label">Niedrigste Höhenlage</string>
<string name="min_grade_label">Minimale Steigung</string>
<string name="min_pace_label">Minimaler Pace</string>
<!-- Min -->
<string name="min_elevation_label">Niedrigste Höhenlage</string>
<string name="min_grade_label">Minimale Steigung</string>
<string name="min_pace_label">Minimaler Pace</string>
<!-- Max -->
<string name="max_elevation_label">Höchste Höhenlage</string>
<string name="max_grade_label">Maximale Steigung</string>
<string name="max_speed_label">Max. Geschwindigkeit</string>
<!-- Max -->
<string name="max_elevation_label">Höchste Höhenlage</string>
<string name="max_grade_label">Maximale Steigung</string>
<string name="max_speed_label">Max. Geschwindigkeit</string>
<string name="loading_track">Lade Track…</string>
<string name="loading_track">Lade Track…</string>
<!-- Chart Settings -->
<string name="chart_settings">Diagramm-Einstellungen</string>
<!-- X Axis -->
<string name="x_axis">X-Achse</string>
<string name="by_distance">Nach Entfernung</string>
<string name="by_time">Nach Zeit</string>
<!-- Chart Settings -->
<string name="chart_settings">Diagramm-Einstellungen</string>
<!-- X Axis -->
<string name="x_axis">X-Achse</string>
<string name="by_distance">Nach Entfernung</string>
<string name="by_time">Nach Zeit</string>
<!-- Y Axis -->
<string name="y_axis">Y-Achse</string>
<!-- Y Axis -->
<string name="y_axis">Y-Achse</string>
<!-- Units -->
<!-- Time -->
<string name="hour">Stunde</string>
<string name="hours">Stunden</string>
<string name="hr">Std</string>
<string name="min">Min</string>
<string name="minute">Minute</string>
<string name="minutes">Minuten</string>
<string name="second">Sekunde</string>
<string name="seconds">Sekunden</string>
<!--string name="milliseconds">ms</string-->
<!-- Units -->
<!-- Time -->
<string name="hour">Stunde</string>
<string name="hours">Stunden</string>
<string name="hr">Std</string>
<string name="minute">Minute</string>
<string name="minutes">Minuten</string>
<string name="second">Sekunde</string>
<string name="seconds">Sekunden</string>
<!-- Distance -->
<!--string name="meter">m</string-->
<!--string name="kilometer">km</string-->
<!-- Distance -->
<string name="kilometers_long">Kilometer</string>
<string name="feet">Fuß</string>
<!--string name="mile">mi</string-->
<string name="miles_long">Meilen</string>
<string name="miles_long">Meilen</string>
<!-- Speed and Pace -->
<!--string name="kilometer_per_hour">km/h</string-->
<string name="kilometer_per_hour_long">Kilometer pro Stunde</string>
<!--string name="min_per_kilometer">min/km</string-->
<string name="per_kilometer">pro Kilometer</string>
<!--string name="mile_per_hour">mi/h</string-->
<string name="per_kilometer">pro Kilometer</string>
<string name="mile_per_hour_long">Meilen pro Stunde</string>
<!--string name="min_per_mile">min/mi</string-->
<string name="per_mile">pro Meile</string>
<string name="per_mile">pro Meile</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">Zeit in Bewegung</string>
<string name="total_time_label">Gesamtzeit</string>
<string name="time_label">Zeit</string>
<string name="sd_unavail">SD-Karte nicht verfügbar</string>
<string name="speed">Geschwindigkeit</string>
<string name="start_trip">Du musst erst eine Aufzeichnung beginnen.</string>
<string name="statistics">Statistik</string>
<string name="total_distance_label">Gesamtentfernung</string>
<string name="distance_label">Entfernung</string>
<string name="power">Kraft</string>
<string name="cadence">Kadenz</string>
<string name="heart_rate">Herzfrequenz</string>
<string name="max_heart_rate">Höchste Herzfrequenz</string>
<!--string name="unknown">-</string-->
<string name="waiting">Bitte warten…</string>
<!-- Stats Labels -->
<string name="moving_time_label">Zeit in Bewegung</string>
<string name="total_time_label">Gesamtzeit</string>
<string name="time_label">Zeit</string>
<string name="sd_unavail">SD-Karte nicht verfügbar</string>
<string name="speed">Geschwindigkeit</string>
<string name="start_trip">Du musst erst eine Aufzeichnung beginnen.</string>
<string name="statistics">Statistik</string>
<string name="total_distance_label">Gesamtentfernung</string>
<string name="distance_label">Entfernung</string>
<string name="power">Kraft</string>
<string name="cadence">Kadenz</string>
<string name="heart_rate">Herzfrequenz</string>
<string name="max_heart_rate">Höchste Herzfrequenz</string>
<string name="waiting">Bitte warten…</string>
<!-- End User License Agreement -->
<string name="eula_title">Lizenzvereinbarung für Endverbraucher</string>
<string name="accept">Akzeptieren</string>
<string name="decline">Ablehnen</string>
<!-- End User License Agreement -->
<string name="eula_title">Lizenzvereinbarung für Endverbraucher</string>
<string name="accept">Akzeptieren</string>
<string name="decline">Ablehnen</string>
<!-- About -->
<string name="about">Über</string>
<string name="help">Hilfe</string>
<!--string name="about_team">Team:</string-->
<!--string name="about_version">Version:</string-->
<!-- About -->
<string name="about">Über</string>
<string name="help">Hilfe</string>
<string name="about_support">Unterstützung:</string>
<string name="about_privacy">Datenschutz:</string>
<!-- Send to Google -->
<string name="sendtogoogle_title">Senden an…</string>
<!--string name="sendtogoogle_google_fusiontables">Google Fusion Tables</string-->
<string name="sendtogoogle_google_docs">Google Text &amp; Tabellen</string>
<string name="sendtogoogle_send_now">Jetzt senden</string>
<string name="sendtogoogle_send_stats">Trackstatistik senden</string>
<string name="sendtogoogle_send_stats_and_points">Statistik und Punkte senden</string>
<string name="sendtogoogle_send_now">Jetzt senden</string>
<string name="sendtogoogle_send_stats">Trackstatistik senden</string>
<string name="sendtogoogle_send_stats_and_points">Statistik und Punkte senden</string>
<!-- Getting the account to upload to. -->
<string name="no_account_found_title">Kein Konto vorhanden</string>
<string name="no_account_found">Kein Konto gefunden, um Tracks zu versenden.</string>
<string name="choose_account_title">Wähle ein Konto</string>
<!-- Getting the account to upload to. -->
<string name="no_account_found_title">Kein Konto vorhanden</string>
<string name="no_account_found">Kein Konto gefunden, um Tracks zu versenden.</string>
<string name="choose_account_title">Wähle ein Konto</string>
<!-- SD card -->
<string name="io_no_external_storage_found">Keine externes Speichermedium verfügbar. Stelle sicher, dass eine SD-Karte vorhanden ist und nicht bereits von einem Computer darauf zugegriffen wird.</string>
<string name="io_write_failed">Die Datei kann nicht geschrieben werden.</string>
<string name="io_read_failed">Die Datei konnte nicht gelesen werden.</string>
<string name="io_create_dir_failed">Das Verzeichnis auf der SD-Karte kann nicht erstellt werden.</string>
<string name="io_write_finished">Der Track wurde auf die SD-Karte geschrieben.</string>
<string name="io_read_finished">Lesen von der SD-Karte beendet.</string>
<!-- SD card -->
<string name="io_no_external_storage_found">Keine externes Speichermedium verfügbar. Stelle sicher, dass eine SD-Karte vorhanden ist und nicht bereits von einem Computer darauf zugegriffen wird.</string>
<string name="io_write_failed">Die Datei kann nicht geschrieben werden.</string>
<string name="io_read_failed">Die Datei konnte nicht gelesen werden.</string>
<string name="io_create_dir_failed">Das Verzeichnis auf der SD-Karte kann nicht erstellt werden.</string>
<string name="io_write_finished">Der Track wurde auf die SD-Karte geschrieben.</string>
<string name="io_read_finished">Lesen von der SD-Karte beendet.</string>
<!-- VersionChecker -->
<string name="version_check_title">Suche nach neuer Version</string>
<string name="version_check_upgrade_button">Jetzt aktualisieren</string>
<string name="version_check_continue_button">Fortfahren, ohne zu aktualisieren</string>
<string name="upgrade_required">Deine Version von %1$s funktioniert möglicherweise nicht mehr richtig und wird nicht mehr unterstützt. Bitte aktualisiere %1$s.</string>
<string name="upgrade_recommended">Deine Version von %1$s funktioniert möglicherweise nicht mehr richtig. Du kannst sie jetzt aktualisieren, oder auf sie auf eigene Gefahr weiterverwenden. Einige Funktionen wie Datenaustausch mit Google-Diensten werden möglicherweise nicht mehr funktionieren, solange Du die Software nicht aktualisierst.</string>
<string name="upgrade_available">Eine neue Version von %1$s ist jetzt verfügbar. Du kannst Deine installierte Version ohne Probleme weiterverwenden, aber um die neuesten Funktionen in Anspruch nehmen zu können, musst Du die Software aktualisieren.</string>
<!-- VersionChecker -->
<string name="version_check_title">Suche nach neuer Version</string>
<string name="version_check_upgrade_button">Jetzt aktualisieren</string>
<string name="version_check_continue_button">Fortfahren, ohne zu aktualisieren</string>
<string name="upgrade_required">Deine Version von %1$s funktioniert möglicherweise nicht mehr richtig und wird nicht mehr unterstützt. Bitte aktualisiere %1$s.</string>
<string name="upgrade_recommended">Deine Version von %1$s funktioniert möglicherweise nicht mehr richtig. Du kannst sie jetzt aktualisieren, oder auf sie auf eigene Gefahr weiterverwenden. Einige Funktionen wie Datenaustausch mit Google-Diensten werden möglicherweise nicht mehr funktionieren, solange Du die Software nicht aktualisierst.</string>
<string name="upgrade_available">Eine neue Version von %1$s ist jetzt verfügbar. Du kannst Deine installierte Version ohne Probleme weiterverwenden, aber um die neuesten Funktionen in Anspruch nehmen zu können, musst Du die Software aktualisieren.</string>
<!-- Welcome -->
<string name="welcome">Willkommen</string>
<!-- Welcome -->
<string name="welcome">Willkommen</string>
<string name="welcome_read_later">OK</string>
<string name="welcome_about">Über My Tracks</string>
<string name="welcome_about">Über My Tracks</string>
<!-- Announcement -->
<string name="announce_no_distance">My Tracks keine Entfernung</string>
<!-- Announcement -->
<string name="announce_no_distance">My Tracks keine Entfernung</string>
<!-- Format:
$1 : Distance label
$2 : Distance value (5)
@@ -407,44 +384,42 @@ limitations under the License.
$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 in %4$s mit %5$s %6$s</string>
-->
<string name="announce_template">My Tracks %1$s %2$.2f %3$s in %4$s mit %5$s %6$s</string>
<!-- Check Units -->
<string name="check_units_title">Einheitenbenachrichtigung</string>
<string name="check_units_message">Voreingestellt sind metrische Einheiten. Willst Du diese Einstellung ändern?</string>
<!-- Check Units -->
<string name="check_units_title">Einheitenbenachrichtigung</string>
<string name="check_units_message">Voreingestellt sind metrische Einheiten. Willst Du diese Einstellung ändern?</string>
<!-- Fake preference keys - never saved, but show options in the preferences screen -->
<string name="method_bluetooth">Bluetooth</string>
<string name="bluetooth_options">Bluetooth-Einstellungen</string>
<string name="bluetooth_pairing">Geräteverbindung</string>
<string name="bluetooth_pairing_summary">Öffnet Androids Bluetooth-Einstellungen, um Geräte zu verbinden.</string>
<!--string name="sensor_bluetooth_options_key">bluetoothSensorsEnabled</string-->
<string name="sensor_options">Sensor-Einstellungen</string>
<string name="bluetooth_options">Bluetooth-Einstellungen</string>
<string name="bluetooth_pairing">Geräteverbindung</string>
<string name="bluetooth_pairing_summary">Öffnet Androids Bluetooth-Einstellungen, um Geräte zu verbinden.</string>
<string name="sensor_options">Sensor-Einstellungen</string>
<!-- Bluetooth Sensor -->
<string name="bluetooth_connected">Verbunden mit %s</string>
<string name="bluetooth_connecting">Verbinde mit Bluetooth-Sensor ...</string>
<string name="bluetooth_not_connected">Bluetooth-Sensor nicht verbunden.</string>
<!-- Bluetooth Sensor -->
<string name="bluetooth_connected">Verbunden mit %s</string>
<string name="bluetooth_connecting">Verbinde mit Bluetooth-Sensor ...</string>
<string name="bluetooth_not_connected">Bluetooth-Sensor nicht verbunden.</string>
<!-- Sensor State -->
<string name="sensor_data_time">Uhrzeit</string>
<string name="power_meter_enabled">Kraftmesser aktiviert</string>
<string name="heart_rate_monitor_enabled">Herzfrequenzmessung aktiviert</string>
<string name="no_sensor_manager">Keine Sensoren verfügbar</string>
<string name="enabled">Aktiviert</string>
<string name="connecting">Verbinde...</string>
<string name="connected">Verbunden</string>
<string name="disconnected">Getrennt</string>
<string name="no_sensor_service">Kein Sensor-Dienst</string>
<string name="searching">Suche...</string>
<string name="sending">Sende...</string>
<!-- Sensor State -->
<string name="sensor_data_time">Uhrzeit</string>
<string name="power_meter_enabled">Kraftmesser aktiviert</string>
<string name="heart_rate_monitor_enabled">Herzfrequenzmessung aktiviert</string>
<string name="no_sensor_manager">Keine Sensoren verfügbar</string>
<string name="enabled">Aktiviert</string>
<string name="connecting">Verbinde...</string>
<string name="connected">Verbunden</string>
<string name="disconnected">Getrennt</string>
<string name="no_sensor_service">Kein Sensor-Dienst</string>
<string name="searching">Suche...</string>
<string name="sending">Sende...</string>
<!-- Manifest description (not seen inside the app) -->
<string name="notification_permission_label">Track-Aufzeichnungs-Benachrichtigungen empfangen</string>
<string name="read_tracks_permission_label">Aufgezeichnete Trackdaten lesen</string>
<string name="write_tracks_permission_label">Aufgezeichnete Trackdaten schreiben, Starten/Anhalten des Aufzeichnens von Tracks</string>
<string name="notification_permission_description">Werde benachrichtigt, wenn die Aufzeichnung eines Tracks beginnt oder anhält.</string>
<string name="read_tracks_permission_description">Ermöglicht das Lesen von Trackdaten wie Messpunkten oder Wegpunkten.</string>
<string name="write_tracks_permission_description">Ermöglicht das Schreiben von Trackdaten wie beim Starten der Aufzeichnung oder beim Hinzufügen von Wegpunkten.</string>
</resources>
<!-- Manifest description (not seen inside the app) -->
<string name="notification_permission_label">Track-Aufzeichnungs-Benachrichtigungen empfangen</string>
<string name="read_tracks_permission_label">Aufgezeichnete Trackdaten lesen</string>
<string name="write_tracks_permission_label">Aufgezeichnete Trackdaten schreiben, Starten/Anhalten des Aufzeichnens von Tracks</string>
<string name="notification_permission_description">Werde benachrichtigt, wenn die Aufzeichnung eines Tracks beginnt oder anhält.</string>
<string name="read_tracks_permission_description">Ermöglicht das Lesen von Trackdaten wie Messpunkten oder Wegpunkten.</string>
<string name="write_tracks_permission_description">Ermöglicht das Schreiben von Trackdaten wie beim Starten der Aufzeichnung oder beim Hinzufügen von Wegpunkten.</string>
</resources>
+1
View File
@@ -47,6 +47,7 @@ limitations under the License.
<string name="tracklist_save_as_tcx">Guardar en archivo TCX</string>
<string name="tracklist_btn_send_all_to_fusiontables">Enviar a Google Fusion Tables</string>
<!-- Export All -->
<string name="tracklist_share_linkfusion">Un enlace a Google Fusion Tables</string>
<string name="tracklist_share_csv_file">Un archivo CSV</string>
<string name="tracklist_share_tcx_file">Un archivo TCX</string>
+1
View File
@@ -121,6 +121,7 @@ limitations under the License.
<string name="tracklist_all_tracks">Todos los recorridos:"</string>
<string name="tracklist_this_track">Este recorrido"</string>
<string name="tracklist_share_track">Compartir con amigos..."</string>
<string name="tracklist_share_linkfusion">Un enlace a Google Fusion Tables</string>
<string name="tracklist_share_gpx_file">Un archivo GPX"</string>
<string name="tracklist_share_kml_file">Un archivo KML"</string>
<string name="tracklist_clear_map">"Limpiar mapa"</string>
+1
View File
@@ -127,6 +127,7 @@ limitations under the License.
<string name="tracklist_all_tracks">Tous les parcours:</string>
<string name="tracklist_this_track">Ce parcours</string>
<string name="tracklist_share_track">Partager...</string>
<string name="tracklist_share_linkfusion">Lien sur Google Fusion Tables</string>
<string name="tracklist_share_gpx_file">Fichier GPX</string>
<string name="tracklist_share_kml_file">Fichier KML</string>
<string name="tracklist_clear_map">Effacer la carte</string>
+1 -1
View File
@@ -129,7 +129,7 @@ limitations under the License.
<string name="tracklist_all_tracks">Tutti i percorsi:</string>
<string name="tracklist_this_track">Questo percorso</string>
<string name="tracklist_share_track">Condividi con amici...</string>
<string name="tracklist_share_link">Un link alla mappa</string>
<!-- <string name="tracklist_share_linkfusion">Un link alla mappa in «Le mie mappe» di Google</string> -->
<string name="tracklist_share_gpx_file">Un file GPX</string>
<string name="tracklist_share_kml_file">Un file KML</string>
<string name="tracklist_clear_map">Cancella la mappa</string>
-7
View File
@@ -287,11 +287,4 @@ limitations under the License.
<item>噴水</item>
<item>ウェイポイント</item>
</array>
<array name="sensor_type_options">
<item>なし</item>
<item>ANT+ センサー</item>
<item>SRM ANT+ ブリッジ</item>
<item>Zephyr Bluetooth</item>
</array>
</resources>
+19 -61
View File
@@ -35,7 +35,6 @@ limitations under the License.
<!-- Error messages -->
<string name="error_no_location_manager">この端末でロケーションマネージャを発見できませんでした.</string>
<string name="error_no_gps_location_provider">この端末でGPSロケーションプロバイダを発見できました.</string>
<string name="error_sending_to_mymap">Googleマイマップへのトラック送信でエラーが発生しました.しばらく待って試して下さい.</string>
<string name="error_sending_to_fusiontables">Google Fusion Tablesへのトラック送信でエラーが発生しました.しばらく待って試して下さい.</string>
<string name="error_sending_to_docs">Google Docsへのトラック送信でエラーが発生しました.しばらく待って試して下さい.</string>
<string name="error_unable_to_start_recording">記録作成開始できません.もう一度試して下さい.</string>
@@ -51,13 +50,11 @@ 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">新しいマイマップをmap.google.comに作成しました.</string>
<string name="status_new_fusiontable_has_been_created">新しいGoogle Fusion Tableをgoogle.com/fusiontablesに作成しました.</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_enable_gps">ここをタップして「位置情報とセキュリティの設定」を開いて「GPS機能を使用」にチェックして下さい.バックボタンで戻ってください.</string>
<string name="status_approximate_location">ご注意: 携帯電話中継局とWi-Fiネットワークから大まかな位置を特定します.</string>
<string name="status_no_location">現在位置決定ができません.位置取得源を増やし(位置情報とセキュリティの設定 をご覧ください)、空が見えるようにして下さい.もう一度試して下さい.</string>
<string name="status_waypoint_inserted">ウェイポイントマーカーを挿入しました.</string>
@@ -65,17 +62,14 @@ limitations under the License.
<!-- Progress dialog -->
<string name="progress_title">お待ちください...</string>
<string name="progress_message">トラックをGoogleに送信しています.</string>
<string name="progress_message">トラックをGoogleに送信しました.</string>
<string name="progress_message_reading_track">トラックを読んでいます...</string>
<string name="progress_message_preparing_track">トラックを準備しています...</string>
<string name="progress_message_authenticating_fusiontables">Google Fusion Tablesへの認証を行っています...</string>
<string name="progress_message_authenticating_mymaps">Googleマップへの認証を行っています...</string>
<string name="progress_message_authenticating_docs">Google Docsへの認証を行っています...</string>
<string name="progress_message_sending_docs">トラックをGoogle Docsに送信しています...</string>
<string name="progress_message_sending_mymaps">トラックをGoogleマップに送信しています...</string>
<string name="progress_message_creating_map">新しいマイマップを作成しています...</string>
<string name="progress_message_sending_fusiontables">トラックをFusion Tablesに送信しています...</string>
<string name="progress_message_creating_fusiontable">新しいFusionテーブルを生成しています...</string>
<string name="progress_message_creating_fusiontable">新しいFusion Tablesを生成しています...</string>
<string name="import_progress_message">GPSトラックをインポートしています.若干時間がかかります.</string>
<string name="write_progress_message">SDカードにデータを書き込んでいます.若干時間がかかります.</string>
<string name="progress_message_updating_track">トラック統計情報を更新しています...</string>
@@ -90,10 +84,6 @@ limitations under the License.
<string name="new_map_description">Android用My Tracksで作成</string>
<string name="fusiontable_link">Android用&lt;a href=\'http://mytracks.appspot.com\'&gt;My Tracks&lt;/a&gt;で作成しました.</string>
<!-- Text and links when uploading to Google My Maps -->
<string name="my_map_link">Android用&lt;a href=\'http://mytracks.appspot.com\'&gt;My Tracks&lt;/a&gt;で作成しました.</string>
<string name="new_map_title">新規マップ</string>
<!-- Formatting of track and marker descriptions -->
<string name="points">ポイント</string>
<string name="recorded_date">記録日</string>
@@ -123,12 +113,10 @@ limitations under the License.
<!-- TrackList -->
<string name="tracklist_show_track">表示</string>
<string name="tracklist_send_to_mymaps">Googleマイマップに送信</string>
<string name="tracklist_send_to_new_mymap">新規Googleマイマップに送信</string>
<string name="tracklist_send_to_fusiontables">Google Fusion Tablesに送信</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_send_to_fusiontables">Google Fusion Tablesへ送信</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>
<string name="tracklist_edit_track">詳細編集</string>
<string name="tracklist_write_to_sd">SDへの書き込み...</string>
@@ -136,33 +124,21 @@ limitations under the License.
<string name="tracklist_save_as_kml">KMLファイルの保存</string>
<string name="tracklist_save_as_csv">CVSファイルの保存</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マイマップに送信</string>
<string name="tracklist_btn_delete_all">全て削除</string>
<string name="tracklist_btn_send_all_to_fusiontables">Google Fusion Tablesへの送信</string>
<string name="tracklist_btn_delete_all">全トラックの削除</string>
<!-- Export All -->
<string name="tracklist_btn_export_all">全て出力</string>
<string name="tracklist_btn_export_all">全トラックの出力</string>
<string name="export_done">出力終了</string>
<string name="tracklist_pick_one">トラックを選択します.オプションを表示するには長押しして下さい.</string>
<string name="tracklist_all_tracks">全トラック:</string>
<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_linkfusion">Google Fusion Tablesへのリンク</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>
<string name="import_done">インポート終了</string>
<!-- Format:
$1 : Successful imports
$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_error">ファイル %s のインポートエラー</string>
<string name="tracklist_clear_map">マップの消去</string>
<!-- Waypoints list -->
<string name="waypointslist_btn_delete_all">全てのマーカーの削除</string>
@@ -215,7 +191,7 @@ limitations under the License.
<string name="settings_map_public">マップの公開</string>
<string name="settings_map_public_summary_on">アップロードされたマップはmaps.google.comで誰でも閲覧できます</string>
<string name="settings_map_public_summary_off">アップロードされたマップはmaps.google.comのリストに公開されません</string>
<string name="settings_map_public_summary_off">アップロードされたマップはmaps.google.comのリストに公開されません.</string>
<string name="settings_report_speed_or_pace">速度表示</string>
<string name="settings_report_speed_or_pace_summary_on">速度が表示されます</string>
@@ -267,23 +243,6 @@ 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マイマップに送信</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">このマップもコンテンツも検索結果に表示されませんが、直接リンクで見られる可能性があります</string>
<!-- Sharing -->
<string name="share_map">マップ共有</string>
<string name="share_map_subject">マップを共有したいと思います</string>
@@ -374,6 +333,7 @@ limitations under the License.
<string name="cadence">ケイデンス</string>
<string name="heart_rate">心拍数</string>
<string name="max_heart_rate">最大心拍数</string>
<string name="unknown">-</string>
<string name="waiting">待機中...</string>
<!-- End User License Agreement -->
@@ -391,10 +351,8 @@ limitations under the License.
<!-- Send to Google -->
<string name="sendtogoogle_title">送信...</string>
<string name="sendtogoogle_google_mymaps">Googleマイマップ</string>
<string name="sendtogoogle_google_fusiontables">Googleマイマップ</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>
@@ -407,7 +365,7 @@ limitations under the License.
<string name="io_no_external_storage_found">外部ストレージを発見できませんでした.SDカードが刺さっているか、端末がコンピュータにマウントされていないか確認してください.</string>
<string name="io_write_failed">ファイルへの書き込みができません.</string>
<string name="io_read_failed">ファイルからの読み込みができません.</string>
<string name="io_create_dir_failed">SDカード上でディレクトリを作成できません.</string>
<string name="io_create_dir_failed">SDカードにディレクトリを作成できません.</string>
<string name="io_write_finished">SDカードへの書き込み終了.</string>
<string name="io_read_finished">SDカードからの読み込み終了.</string>
@@ -440,11 +398,11 @@ limitations under the License.
<string name="check_units_message">デフォルトの単位はメートルです.設定を変更しますか?</string>
<!-- Fake preference keys - never saved, but show options in the preferences screen -->
<!-- string name="method_bluetooth">Bluetooth</string --> <!-- duplicate -->
<string name="bluetooth_options">Bluetoothオプション</string>
<string name="bluetooth_pairing">ペアリング</string>
<string name="bluetooth_pairing_summary">ペアリングを行うには「Bluetooth設定」を開いて下さい</string>
<string name="sensor_bluetooth_options_key">bluetoothSensorsEnabled</string>
<string name="ant_options">ANTオプション</string>
<string name="sensor_options">センサーオプション</string>
<!-- Bluetooth Sensor -->
@@ -468,7 +426,7 @@ limitations under the License.
<!-- Manifest description (not seen inside the app) -->
<string name="notification_permission_label">トラック記録通知受信</string>
<string name="read_tracks_permission_label">トラック読み込み</string>
<string name="write_tracks_permission_label">トラック書き込みとトラック記録の開始・終了</string>
<string name="write_tracks_permission_label">トラック書き込み トラック記録の開始・終了</string>
<string name="notification_permission_description">トラック記録の開始・終了時に通知されます.</string>
<string name="read_tracks_permission_description">ポイントやウェイポイントといったトラックの読み込みを可能にします.</string>
<string name="write_tracks_permission_description">記録開始やウェイポイント追加といったトラック記録を可能にします.</string>
+1
View File
@@ -131,6 +131,7 @@ limitations under the License.
<string name="tracklist_all_tracks">Wszystkie trasy:</string>
<string name="tracklist_this_track">Ta trasa</string>
<string name="tracklist_share_track">Podziel się z przyjaciółmi...</string>
<!-- <string name="tracklist_share_linkfusion">Link do Moich Map Google</string> -->
<string name="tracklist_share_gpx_file">Plik GPX</string>
<string name="tracklist_share_kml_file">PLik KML</string>
<string name="tracklist_share_csv_file">Plik CSV</string>
+27 -27
View File
@@ -18,9 +18,9 @@ limitations under the License.
<!-- Used by the Menu -->
<string name="start_recording">Gravar caminho</string>
<string name="stop_recording">Para gravação</string>
<string name="switch_to_sat">Modo do satélite</string>
<string name="switch_to_map">Modo do mapa</string>
<string name="mylocation">Minha Localização</string>
<string name="switch_to_sat">Modo do satélite"</string>
<string name="switch_to_map">Modo do mapa"</string>
<string name="mylocation">Minha Localização"</string>
<string name="list_tracks">Caminhos</string>
<string name="list_markers">Marcadores</string>
<string name="delete_all_tracks">Apagar todos os caminhos</string>
@@ -31,10 +31,10 @@ limitations under the License.
<string name="current_segment">Último segmento</string>
<!-- Error messages -->
<string name="error_no_location_manager">Gerenciador de localização não encontrado neste dispositivo!</string>
<string name="error_no_gps_location_provider">"Provedor de posição de GPS não encontrado neste dispositivo.</string>
<string name="error_sending_to_fusiontables">Ocorreu um erro ao enviar seu caminho para o Google Fusion Tables. Por favor tente novamente mais tarde.</string>
<string name="error_sending_to_docs">Ocorreu um erro ao enviar seu caminho para o Google Docs. Por favor tente novamente mais tarde.</string>
<string name="error_no_location_manager">Gerenciador de localização não encontrado neste dispositivo!"</string>
<string name="error_no_gps_location_provider">"Provedor de posição de GPS não encontrado neste dispositivo."</string>
<string name="error_sending_to_fusiontables">Ocorreu um erro ao enviar seu caminho para o Google Fusion Tables. Por favor tente novamente mais tarde."</string>
<string name="error_sending_to_docs">Ocorreu um erro ao enviar seu caminho para o Google Docs. Por favor tente novamente mais tarde."</string>
<string name="error_unable_to_start_recording">Impossível iniciar a gravação. Tente novamente.</string>
<string name="error_unable_to_stop_recording">Impossível interromper a gravação. Tente novamente.</string>
<string name="error_unable_to_read_file">Impossível ler do arquivo.</string>
@@ -52,7 +52,7 @@ limitations under the License.
<string name="status_tracks_have_been_uploaded">Seu caminho foi enviado para maps.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_new_doc">Seu caminho foi enviado para uma nova planilha em docs.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_docs">Seu caminho foi enviado para docs.google.com.</string>
<string name="status_enable_gps">"Por favor pressione aqui para ir aos ajustes de segurança e localização e verifique que o GPS esteja habilitado. Pressione o botão de voltar para retornar.</string>
<string name="status_enable_gps">"Por favor pressione aqui para ir aos ajustes de segurança e localização e verifique que o GPS esteja habilitado. Pressione o botão de voltar para retornar."</string>
<string name="status_approximate_location">Nota: Uma localização aproximada, determinada por torres de telefonia celular, está sendo mostrada.</string>
<string name="status_no_location">Sua localização não pôde ser determinada. Habilite fontes adicionais de localização (veja configurações de Segurança e Localização) e assegure-se de que o céu está visível.</string>
<string name="status_waypoint_inserted">Um marcador de ponto de passagem foi inserido.</string>
@@ -79,19 +79,19 @@ limitations under the License.
<string name="marker_will_be_permanently_deleted">O marcador será permanentemente apagado deste telefone.</string>
<!-- Text and links when uploading to Google My Maps -->
<string name="new_map_description">"Criado por My Tracks no Android.</string>
<string name="fusiontable_link">"Criado por &lt;a href='http://mytracks.appspot.com'&gt;My Tracks&lt;/a&gt; no Android.</string>
<string name="new_map_description">"Criado por My Tracks no Android."</string>
<string name="fusiontable_link">"Criado por &lt;a href='http://mytracks.appspot.com'&gt;My Tracks&lt;/a&gt; no Android."</string>
<!-- Formatting of track and marker descriptions -->
<string name="points">Pontos</string>
<string name="recorded_date">Gravado</string>
<string name="category">"Tipo de atividade</string>
<string name="waypoint_category">"Tipo de marcador</string>
<string name="part">"(Parte %d)</string>
<string name="recorded_date">Gravado"</string>
<string name="category">"Tipo de atividade"</string>
<string name="waypoint_category">"Tipo de marcador"</string>
<string name="part">"(Parte %d)"</string>
<!-- Used by the track recording service -->
<string name="recording_your_track">"Gravando seu caminho...</string>
<string name="new_track">"Caminho %d</string>
<string name="recording_your_track">"Gravando seu caminho..."</string>
<string name="new_track">"Caminho %d"</string>
<!-- Common -->
<string name="no">Não</string>
@@ -122,22 +122,22 @@ limitations under the License.
<string name="tracklist_btn_send_all_to_fusiontables">Enviar para o Google Fusion Tables</string>
<string name="tracklist_btn_delete_all">Apagar todos os caminhos</string>
<string name="tracklist_pick_one">Escolha um caminho. Pressione&amp;segure para mais opções.</string>
<string name="tracklist_all_tracks">Todos os Caminhos:</string>
<string name="tracklist_this_track">Este Caminho</string>
<string name="tracklist_share_track">Compartilhar com amigos...</string>
<string name="tracklist_share_link">Um link para a mapa</string>
<string name="tracklist_share_gpx_file">Um arquivo GPX</string>
<string name="tracklist_share_kml_file">Um arquivo KML</string>
<string name="tracklist_clear_map">Limpar mapa</string>
<string name="tracklist_all_tracks">Todos os Caminhos:"</string>
<string name="tracklist_this_track">Este Caminho"</string>
<string name="tracklist_share_track">Compartilhar com amigos..."</string>
<string name="tracklist_share_linkfusion">Um link para a Google Fusion Table"</string>
<string name="tracklist_share_gpx_file">Um arquivo GPX"</string>
<string name="tracklist_share_kml_file">Um arquivo KML"</string>
<string name="tracklist_clear_map">"Limpar mapa"</string>
<!-- Waypoints list -->
<string name="waypointslist_btn_delete_all">Apagar todos os marcadores</string>
<string name="waypointslist_this_waypoint">Este Marcador</string>
<string name="waypointslist_delete_waypoint">Apagar</string>
<string name="waypointslist_edit_waypoint">Editar detalhes</string>
<string name="waypointslist_show_waypoint">Mostrar no mapa</string>
<string name="waypointslist_btn_insert_waypoint">Inserir ponto no caminho</string>
<string name="waypointslist_btn_insert_statistics">Inserir estatísticas</string>
<string name="waypointslist_edit_waypoint">Editar detalhes"</string>
<string name="waypointslist_show_waypoint">Mostrar no mapa"</string>
<string name="waypointslist_btn_insert_waypoint">Inserir ponto no caminho"</string>
<string name="waypointslist_btn_insert_statistics">Inserir estatísticas"</string>
<string name="waypointslist_pick_one">Escolha um marcador. Pressione&amp;segure para mais opções.</string>
<!-- MyTracks Details -->
+1
View File
@@ -131,6 +131,7 @@ limitations under the License.
<string name="tracklist_all_tracks">Alla spår:</string>
<string name="tracklist_this_track">Det här spåret</string>
<string name="tracklist_share_track">Dela med vänner...</string>
<!-- <string name="tracklist_share_linkfusion">En länk till Google Mina Kartor</string> -->
<string name="tracklist_share_gpx_file">En GPX-fil</string>
<string name="tracklist_share_kml_file">En KML-fil</string>
<string name="tracklist_share_csv_file">En CSV-fil</string>
+1
View File
@@ -132,6 +132,7 @@ 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_linkfusion">链接到 Google Fusion Table</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>
-6
View File
@@ -406,10 +406,4 @@ limitations under the License.
<item>@string/zephyr_sensor_type</item>
</array>
<!-- DO NOT TRANSLATE -->
<string-array name="ant_sensor_type_values">
<item>@string/ant_sensor_type</item>
<item>@string/srm_ant_bridge_sensor_type</item>
</string-array>
</resources>
-5
View File
@@ -34,9 +34,4 @@ limitations under the License.
<string name="ant_sensor_type">ANT</string>
<string name="srm_ant_bridge_sensor_type">SRM_ANT_BRIDGE</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>
</resources>
-5
View File
@@ -36,7 +36,6 @@ limitations under the License.
<string name="send_stats_and_points_key">sendStatsAndPoints</string>
<string name="send_to_docs_key">sendToDocs</string>
<string name="send_to_my_maps_key">sendToMyMaps</string>
<string name="send_to_fusion_tables_key">sendToFusionTables</string>
<string name="sensor_type_key">sensorType</string>
<string name="share_url_only_key">shareUrlOnly</string>
<string name="split_frequency_key">splitFrequency</string>
@@ -50,8 +49,4 @@ limitations under the License.
<!-- Keys for non-persisted preferences - DO NOT TRANSLATE -->
<string name="backup_to_sd_key">backupToSd</string>
<string name="restore_from_sd_key">restoreFromSd</string>
<!-- Inoperative keys used for the location of preferences items -->
<string name="sensor_options_key">sensorOptions</string>
<string name="ant_options_key">antOptions</string>
</resources>
+7 -54
View File
@@ -35,10 +35,8 @@ limitations under the License.
<!-- Error messages -->
<string name="error_no_location_manager">No location manager was found on this device!</string>
<string name="error_no_gps_location_provider">No GPS location provider was found on this device.</string>
<string name="error_sending_to_mymap">There was an error while sending your track to Google My Map.</string>
<string name="error_sending_to_fusiontables">There was an error while sending your track to Google Fusion Tables.</string>
<string name="error_sending_to_docs">There was an error while sending your track to Google Docs.</string>
<string name="error_please_try_again_later">Please try again later.</string>
<string name="error_sending_to_fusiontables">There was an error while sending your track to Google Fusion Tables. Please try again later.</string>
<string name="error_sending_to_docs">There was an error while sending your track to Google Docs. Please try again later.</string>
<string name="error_unable_to_start_recording">Unable to start recording. Try again.</string>
<string name="error_unable_to_stop_recording">Unable to stop recording. Try again.</string>
<string name="error_unable_to_read_file">Unable to read from file.</string>
@@ -52,30 +50,23 @@ limitations under the License.
<string name="wait_for_fix">Waiting for a better GPS fix. Make sure the sky is visible.</string>
<string name="status_now_recording">Now recording a new track.</string>
<string name="status_stopped_recording">Stopped recording your track.</string>
<string name="status_new_mymap_has_been_created">A new Google My Map has been created at maps.google.com.</string>
<string name="status_new_fusiontable_has_been_created">A new Google Fusion table has been created at google.com/fusiontables.</string>
<string name="status_tracks_have_been_uploaded">Your track has been sent to maps.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_new_doc">Your track has been sent to a new spreadsheet at docs.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_docs">Your track has been sent to docs.google.com.</string>
<string name="status_mymap_info">It may take a few minutes before new tracks appear.</string>
<string name="status_enable_gps">Please tap here to go to Security and Location Settings and check \'enable GPS satellites\'. Press back button to return.</string>
<string name="status_approximate_location">Note: An approximate location as determined from cell towers and WIFI networks is shown.</string>
<string name="status_no_location">A location can currently not be determined. Enable more location sources (see Security and Location Settings) and make sure the sky is visible. Try again later.</string>
<string name="status_waypoint_inserted">A way point marker was inserted.</string>
<string name="status_statistics_inserted">A statistics marker was inserted.</string>
<string name="status_track_upload_status">Upload status:</string>
<!-- Progress dialog -->
<string name="progress_title">Please wait...</string>
<string name="progress_message">Sending your track to Google.</string>
<string name="progress_message_reading_track">Reading track...</string>
<string name="progress_message_preparing_track">Preparing track...</string>
<string name="progress_message_authenticating_fusiontables">Authenticating to Google Fusion Tables...</string>
<string name="progress_message_authenticating_mymaps">Authenticating to Google Maps...</string>
<string name="progress_message_authenticating_docs">Authenticating to Google Docs...</string>
<string name="progress_message_sending_docs">Sending track to Google Docs...</string>
<string name="progress_message_sending_mymaps">Sending track to Google Maps...</string>
<string name="progress_message_creating_map">Creating new My Map...</string>
<string name="progress_message_sending_fusiontables">Sending track to Fusion Tables...</string>
<string name="progress_message_creating_fusiontable">Creating new Fusion table...</string>
<string name="import_progress_message">Importing a GPS track. This may take a while.</string>
@@ -92,10 +83,6 @@ limitations under the License.
<string name="new_map_description">Created by My Tracks on Android.</string>
<string name="fusiontable_link">Created by &lt;a href=\'http://mytracks.appspot.com\'&gt;My Tracks&lt;/a&gt; on Android.</string>
<!-- Text and links when uploading to Google My Maps -->
<string name="my_map_link">Created by &lt;a href=\'http://mytracks.appspot.com\'&gt;My Tracks&lt;/a&gt; on Android.</string>
<string name="new_map_title">New map</string>
<!-- Formatting of track and marker descriptions -->
<string name="points">Points</string>
<string name="recorded_date">Recorded</string>
@@ -126,8 +113,6 @@ limitations under the License.
<!-- TrackList -->
<string name="tracklist_show_track">Show</string>
<string name="tracklist_send_to_mymaps">Send to Google My Maps</string>
<string name="tracklist_send_to_new_mymap">Send to New Google My Map</string>
<string name="tracklist_send_to_fusiontables">Send to Google Fusion Tables</string>
<string name="tracklist_send_to_new_fusiontable">Send to New Google Fusion Table</string>
<string name="tracklist_send_to_docs">Send to Google Docs</string>
@@ -140,32 +125,20 @@ limitations under the License.
<string name="tracklist_save_as_csv">Save a CSV file</string>
<string name="tracklist_save_as_tcx">Save a TCX file</string>
<string name="tracklist_btn_send_all_to_fusiontables">Send to Google Fusion Tables</string>
<string name="tracklist_btn_send_all_to_mymaps">Send to Google My Maps</string>
<string name="tracklist_btn_delete_all">Delete all</string>
<string name="tracklist_btn_delete_all">Delete all tracks</string>
<!-- Export All -->
<string name="tracklist_btn_export_all">Export all</string>
<string name="tracklist_btn_export_all">Export all tracks</string>
<string name="export_done">Export finished</string>
<string name="tracklist_pick_one">Pick a track. Press&amp;hold for more options.</string>
<string name="tracklist_all_tracks">All Tracks:</string>
<string name="tracklist_this_track">This Track</string>
<string name="tracklist_share_track">Share with Friends...</string>
<string name="tracklist_share_link">A link to the map</string>
<string name="tracklist_share_linkfusion">A link to Google Fusion Tables</string>
<string name="tracklist_share_gpx_file">A GPX file</string>
<string name="tracklist_share_kml_file">A KML file</string>
<string name="tracklist_share_csv_file">A CSV file</string>
<string name="tracklist_share_tcx_file">A TCX file</string>
<string name="tracklist_clear_map">Clear map</string>
<!-- Import All -->
<string name="tracklist_btn_import_all">Import all</string>
<string name="import_done">Import finished, imported</string>
<!-- Format:
$1 : Successful imports
$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_error">Import error for file %s</string>
<!-- Waypoints list -->
<string name="waypointslist_btn_delete_all">Delete all markers</string>
@@ -245,7 +218,7 @@ limitations under the License.
<string name="settings_sensor_type_summary">The type of sensor to connect to</string>
<string name="settings_heart_rate_ant_sensor_id">Clear ANT heart rate sensor pairing</string>
<string name="settings_power_ant_sensor_id">Clear ANT power sensor pairing</string>
<string name="settings_srm_bridge_ant_sensor_id">Clear ANT SRM bridge sensor pairing</string>
<string name="settings_srm_bridge_ant_sensor_id">Clear ANT srm bridge sensor pairing</string>
<string name="settings_ant_not_paired">ANT sensor not paired</string>
<string name="settings_ant_paired">ANT sensor paired with: %d</string>
<string name="bluetooth_sensor_title">Bluetooth sensor</string>
@@ -270,23 +243,6 @@ limitations under the License.
<!-- MyTracksSky -->
<string name="mytracks_sky">GPS Satellites</string>
<!-- My Maps -->
<string name="select_map_message">Pick a map from your account:</string>
<string name="create_new_map">Create new map...</string>
<string name="map_list_title">Send to Google My Maps</string>
<string name="maps_list_loading">Loading maps...</string>
<string name="maps_list_failed">Your maps could not be loaded at this time!</string>
<string name="open_map">Select this Map</string>
<string name="edit_map_details">Edit Map Details</string>
<string name="share_track">Share Track</string>
<string name="delete_map">Delete Map from your Account</string>
<string name="map_title">Map Title:</string>
<string name="map_description">Map Description:</string>
<string name="map_searchable_edit">Make this map and its contents show up in search results</string>
<string name="map_not_searchable_edit">Do not let this map or its contents show up in search results, though they may still be viewed be others through the direct URL</string>
<string name="map_searchable">This map and its contents will show in search results</string>
<string name="map_not_searchable">Neither this map nor its contents will show in search results, but they may still be viewed by others through a direct link</string>
<!-- Sharing -->
<string name="share_map">Share map with friends</string>
<string name="share_map_subject">I would like to share a track with you</string>
@@ -297,6 +253,7 @@ limitations under the License.
<string name="send_track_body_format">I think you might be interested in this track.
To view this track use Google Earth or other mapping software.</string>
<string name="share_track">Share track with friends</string>
<!-- Visibility -->
<string name="public_map">Public</string>
@@ -409,11 +366,8 @@ limitations under the License.
<!-- Send to Google -->
<string name="sendtogoogle_title">Send to...</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">Send now</string>
<string name="sendtogoogle_create_new_map">Create a new map</string>
<string name="sendtogoogle_pick_existing_map">Pick an existing map</string>
<string name="sendtogoogle_send_stats">Send track statistics</string>
<string name="sendtogoogle_send_stats_and_points">Send statistics and points</string>
@@ -465,7 +419,6 @@ limitations under the License.
<string name="bluetooth_pairing">Device pairing</string>
<string name="bluetooth_pairing_summary">Open Android\'s bluetooth settings to pair a device</string>
<string name="sensor_bluetooth_options_key">bluetoothSensorsEnabled</string>
<string name="ant_options">ANT options</string>
<string name="sensor_options">Sensor Options</string>
<!-- Bluetooth Sensor -->
+12 -15
View File
@@ -102,8 +102,7 @@ limitations under the License.
</PreferenceScreen>
<!-- Sensors -->
<PreferenceScreen android:title="@string/sensor_options"
android:key="@string/sensor_options_key">
<PreferenceScreen android:title="@string/sensor_options">
<ListPreference android:key="@string/sensor_type_key"
android:title="@string/settings_sensor_type"
android:summary="@string/settings_sensor_type_summary"
@@ -123,22 +122,20 @@ limitations under the License.
android:summary="@string/bluetooth_pairing_summary"
android:persistent="false" />
</PreferenceCategory>
<com.google.android.apps.mytracks.AntPreference
android:key="@string/ant_heart_rate_sensor_id_key"
android:title="@string/settings_heart_rate_ant_sensor_id"/>
<PreferenceCategory android:title="@string/ant_options"
android:key="@string/ant_options_key">
<com.google.android.apps.mytracks.AntPreference
android:key="@string/ant_heart_rate_sensor_id_key"
android:title="@string/settings_heart_rate_ant_sensor_id"/>
<!--
<com.google.android.apps.mytracks.AntPreference
android:key="@string/ant_power_sensor_id_key"
android:title="@string/settings_power_ant_sensor_id"/>
<com.google.android.apps.mytracks.AntPreference
android:key="@string/ant_power_sensor_id_key"
android:title="@string/settings_power_ant_sensor_id"/>
-->
<com.google.android.apps.mytracks.AntPreference
android:key="@string/ant_srm_bridge_sensor_id_key"
android:title="@string/settings_srm_bridge_ant_sensor_id"/>
</PreferenceCategory>
<com.google.android.apps.mytracks.AntPreference
android:key="@string/ant_srm_bridge_sensor_id_key"
android:title="@string/settings_srm_bridge_ant_sensor_id"/>
</PreferenceScreen>
<!-- Sharing settings -->
+8
View File
@@ -28,6 +28,14 @@ package com.dsi.ant;
*/
public class AntDefine {
//////////////////////////////////////////////
// Library Version Information
//////////////////////////////////////////////
public static final int ANT_LIBRARY_VERSION_CODE = 5;
public static final int ANT_LIBRARY_VERSION_MAJOR = 1;
public static final int ANT_LIBRARY_VERSION_MINOR = 4;
public static final String ANT_LIBRARY_VERSION_NAME = String.valueOf(ANT_LIBRARY_VERSION_MAJOR) + "." + String.valueOf(ANT_LIBRARY_VERSION_MINOR);
//////////////////////////////////////////////
// Valid Configuration Values
//////////////////////////////////////////////
File diff suppressed because it is too large Load Diff
@@ -22,16 +22,13 @@ package com.dsi.ant;
*/
public interface AntInterfaceIntent {
public static final String STATUS = "com.dsi.ant.rx.intent.STATUS";
public static final String ANT_MESSAGE = "com.dsi.ant.intent.ANT_MESSAGE";
public static final String ANT_INTERFACE_CLAIMED_PID = "com.dsi.ant.intent.ANT_INTERFACE_CLAIMED_PID";
public static final String STATUS = "com.dsi.ant.rx.intent.STATUS";
public static final String ANT_MESSAGE = "com.dsi.ant.intent.ANT_MESSAGE";
public static final String ANT_ENABLED_ACTION = "com.dsi.ant.intent.action.ANT_ENABLED";
public static final String ANT_DISABLED_ACTION = "com.dsi.ant.intent.action.ANT_DISABLED";
public static final String ANT_RESET_ACTION = "com.dsi.ant.intent.action.ANT_RESET";
public static final String ANT_INTERFACE_CLAIMED_ACTION = "com.dsi.ant.intent.action.ANT_INTERFACE_CLAIMED_ACTION";
public static final String ANT_RX_MESSAGE_ACTION = "com.dsi.ant.intent.action.ANT_RX_MESSAGE_ACTION";
}
-77
View File
@@ -1,77 +0,0 @@
/*
* Copyright 2011 Dynastream Innovations 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.dsi.ant;
/**
* The Android Ant API is not finalized, and *will* be updated and expanded.
* This is the base level ANT messaging API and gives any application full
* control over the ANT radio HW. Caution should be exercised when using
* this interface.
*
* Public API for controlling the Ant Service.
*
* {@hide}
*/
interface IAnt_6 {
// Since version 1 (1.0):
boolean enable();
boolean disable();
boolean isEnabled();
boolean ANTTxMessage(in byte[] message);
boolean ANTResetSystem();
boolean ANTUnassignChannel(byte channelNumber);
boolean ANTAssignChannel(byte channelNumber, byte channelType, byte networkNumber);
boolean ANTSetChannelId(byte channelNumber, int deviceNumber, byte deviceType, byte txType);
boolean ANTSetChannelPeriod(byte channelNumber, int channelPeriod);
boolean ANTSetChannelRFFreq(byte channelNumber, byte radioFrequency);
boolean ANTSetChannelSearchTimeout(byte channelNumber, byte searchTimeout);
boolean ANTSetLowPriorityChannelSearchTimeout(byte channelNumber, byte searchTimeout);
boolean ANTSetProximitySearch(byte channelNumber, byte searchThreshold);
boolean ANTSetChannelTxPower(byte channelNumber, byte txPower);
boolean ANTAddChannelId(byte channelNumber, int deviceNumber, byte deviceType, byte txType, byte listIndex);
boolean ANTConfigList(byte channelNumber, byte listSize, byte exclude);
boolean ANTOpenChannel(byte channelNumber);
boolean ANTCloseChannel(byte channelNumber);
boolean ANTRequestMessage(byte channelNumber, byte messageID);
boolean ANTSendBroadcastData(byte channelNumber, in byte[] txBuffer);
boolean ANTSendAcknowledgedData(byte channelNumber, in byte[] txBuffer);
boolean ANTSendBurstTransferPacket(byte control, in byte[] txBuffer);
int ANTSendBurstTransfer(byte channelNumber, in byte[] txBuffer);
int ANTTransmitBurst(byte channelNumber, in byte[] txBuffer, int initialPacket, boolean containsEndOfBurst);
// Since version 4 (1.3):
boolean ANTConfigEventBuffering(int screenOnFlushTimerInterval, int screenOnFlushBufferThreshold, int screenOffFlushTimerInterval, int screenOffFlushBufferThreshold);
// Since version 2 (1.1):
boolean ANTDisableEventBuffering();
// Since version 3 (1.2):
int getServiceLibraryVersionCode();
String getServiceLibraryVersionName();
// Since version 6 (1.5):
boolean claimInterface();
boolean requestForceClaimInterface(String appName);
boolean stopRequestForceClaimInterface();
boolean releaseInterface();
boolean hasClaimedInterface();
}
-35
View File
@@ -1,35 +0,0 @@
/*
* Copyright 2011 Dynastream Innovations 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.dsi.ant;
/**
* Defines version numbers
*
* @hide
*/
public class Version {
//////////////////////////////////////////////
// Library Version Information
//////////////////////////////////////////////
public static final int ANT_LIBRARY_VERSION_CODE = 6;
public static final int ANT_LIBRARY_VERSION_MAJOR = 2;
public static final int ANT_LIBRARY_VERSION_MINOR = 0;
public static final String ANT_LIBRARY_VERSION_NAME = String.valueOf(ANT_LIBRARY_VERSION_MAJOR) + "." + String.valueOf(ANT_LIBRARY_VERSION_MINOR);
}
@@ -1,20 +0,0 @@
package com.dsi.ant.exception;
public class AntInterfaceException extends Exception
{
/**
*
*/
private static final long serialVersionUID = -7278855366167722274L;
public AntInterfaceException()
{
this("Unknown ANT Interface error");
}
public AntInterfaceException(String string)
{
super(string);
}
}
@@ -1,23 +0,0 @@
package com.dsi.ant.exception;
import android.os.RemoteException;
public class AntRemoteException extends AntInterfaceException
{
/**
*
*/
private static final long serialVersionUID = 8950974759973459561L;
public AntRemoteException(RemoteException e)
{
this("ANT Interface error, ANT Radio Service remote error: "+e.toString(), e);
}
public AntRemoteException(String string, RemoteException e)
{
super(string);
this.initCause(e);
}
}
@@ -1,19 +0,0 @@
package com.dsi.ant.exception;
public class AntServiceNotConnectedException extends AntInterfaceException
{
/**
*
*/
private static final long serialVersionUID = -2085081032170129309L;
public AntServiceNotConnectedException()
{
this("ANT Interface error, ANT Radio Service not connected.");
}
public AntServiceNotConnectedException(String string)
{
super(string);
}
}
@@ -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,20 +15,20 @@
*/
package com.google.android.apps.mytracks;
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.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager.BadTokenException;
/**
* A class to handle all dialog related events for My Tracks.
*
*
* @author Sandor Dornbush
*/
public class DialogManager {
@@ -37,12 +37,14 @@ public class DialogManager {
public static final int DIALOG_IMPORT_PROGRESS = 2;
public static final int DIALOG_PROGRESS = 3;
public static final int DIALOG_SEND_TO_GOOGLE = 4;
public static final int DIALOG_WRITE_PROGRESS = 5;
public static final int DIALOG_SEND_TO_GOOGLE_RESULT = 5;
public static final int DIALOG_WRITE_PROGRESS = 6;
private ProgressDialog progressDialog;
private ProgressDialog importProgressDialog;
private ProgressDialog writeProgressDialog;
private SendDialog sendToGoogleDialog;
private SendToGoogleDialog sendToGoogleDialog;
private AlertDialog sendToGoogleResultDialog;
private ChartSettingsDialog chartSettingsDialog;
private MyTracks activity;
@@ -50,7 +52,7 @@ public class DialogManager {
public DialogManager(MyTracks activity) {
this.activity = activity;
}
protected Dialog onCreateDialog(int id, Bundle args) {
switch (id) {
case DIALOG_CHART_SETTINGS:
@@ -75,8 +77,23 @@ public class DialogManager {
progressDialog.setProgress(10);
return progressDialog;
case DIALOG_SEND_TO_GOOGLE:
sendToGoogleDialog = new SendDialog(activity);
sendToGoogleDialog = new SendToGoogleDialog(activity);
return sendToGoogleDialog;
case DIALOG_SEND_TO_GOOGLE_RESULT:
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setIcon(android.R.drawable.ic_dialog_info);
builder.setTitle("Title");
builder.setMessage("Message");
builder.setPositiveButton(activity.getString(R.string.ok), null);
builder.setNeutralButton(activity.getString(R.string.share_track),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
activity.shareLinkToFusionTable(activity.sendToTrackId);
dialog.dismiss();
}
});
sendToGoogleResultDialog = builder.create();
return sendToGoogleResultDialog;
case DIALOG_WRITE_PROGRESS:
writeProgressDialog = new ProgressDialog(activity);
writeProgressDialog.setIcon(android.R.drawable.ic_dialog_info);
@@ -95,6 +112,22 @@ public class DialogManager {
case DIALOG_SEND_TO_GOOGLE:
activity.resetSendToGoogleStatus();
break;
case DIALOG_SEND_TO_GOOGLE_RESULT:
boolean success = activity.getSendToGoogleSuccess();
sendToGoogleResultDialog.setTitle(
success ? R.string.success : R.string.error);
sendToGoogleResultDialog.setIcon(success
? android.R.drawable.ic_dialog_info
: android.R.drawable.ic_dialog_alert);
sendToGoogleResultDialog.setMessage(activity.getFusionTablesResultMessage());
boolean canShare = activity.getSendToFusionTablesTableId() != null;
View share =
sendToGoogleResultDialog.findViewById(android.R.id.button3);
if (share != null) {
share.setVisibility(canShare ? View.VISIBLE : View.GONE);
}
break;
case DIALOG_CHART_SETTINGS:
Log.d(MyTracksConstants.TAG, "MyTracks.onPrepare chart dialog");
chartSettingsDialog.setup(activity.getChartActivity());
@@ -113,7 +146,7 @@ public class DialogManager {
}
});
}
public void setProgressValue(final int percent) {
activity.runOnUiThread(new Runnable() {
public void run() {
@@ -129,7 +162,7 @@ public class DialogManager {
/**
* @return the sendToGoogleDialog
*/
public SendDialog getSendToGoogleDialog() {
public SendToGoogleDialog getSendToGoogleDialog() {
return sendToGoogleDialog;
}
@@ -158,9 +191,9 @@ public class DialogManager {
}
/**
* 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.
* Just like showDialog, but will catch a 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
*/
@@ -180,24 +213,6 @@ public class DialogManager {
});
}
/**
* The equivalent of {@link #showDialogSafely(int)}, but for a specific
* dialog instance.
*/
public static void showDialogSafely(Activity activity, final Dialog dialog) {
activity.runOnUiThread(new Runnable() {
public void run() {
try {
dialog.show();
} catch (BadTokenException e) {
Log.w(MyTracksConstants.TAG, "Could not display dialog", e);
} catch (IllegalStateException e) {
Log.w(MyTracksConstants.TAG, "Could not display dialog", e);
}
}
});
}
/**
* Dismisses the progress dialog if it is showing. Executed on the UI thread.
*/
@@ -20,17 +20,18 @@ import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.io.TrackWriter;
import com.google.android.apps.mytracks.io.TrackWriterFactory;
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.util.MyTracksUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.widget.Toast;
@@ -120,7 +121,7 @@ public class ExportAllTracks {
prefs.getLong(activity.getString(R.string.recording_track_key), -1);
}
if (recordingTrackId != -1) {
wakeLock = MyTracksUtils.acquireWakeLock(activity, wakeLock);
acquireWakeLock();
}
// Now we can safely export everything.
@@ -210,4 +211,40 @@ public class ExportAllTracks {
}
}
}
/**
* Tries to acquire a partial wake lock if not already acquired. Logs errors
* and gives up trying in case the wake lock cannot be acquired.
*/
private void acquireWakeLock() {
Log.i(MyTracksConstants.TAG, "ExportAllTracks: Aquiring wake lock.");
try {
PowerManager pm =
(PowerManager) activity.getSystemService(Context.POWER_SERVICE);
if (pm == null) {
Log.e(MyTracksConstants.TAG,
"ExportAllTracks: Power manager not found!");
return;
}
if (wakeLock == null) {
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
MyTracksConstants.TAG);
if (wakeLock == null) {
Log.e(MyTracksConstants.TAG,
"ExportAllTracks: Could not create wake lock (null).");
return;
}
}
if (!wakeLock.isHeld()) {
wakeLock.acquire();
if (!wakeLock.isHeld()) {
Log.e(MyTracksConstants.TAG,
"ExportAllTracks: Could not acquire wake lock.");
}
}
} catch (RuntimeException e) {
Log.e(MyTracksConstants.TAG,
"ExportAllTracks: Caught unexpected exception: " + e.getMessage(), e);
}
}
}
@@ -1,217 +0,0 @@
/*
* 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 com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.io.GpxImporter;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.MyTracksUtils;
import com.google.android.maps.mytracks.R;
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;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
/**
* A class that will import all GPX tracks in /sdcard/MyTracks/gpx/
*
* @author David Piggott
*/
public class ImportAllTracks {
private final Activity activity;
private WakeLock wakeLock;
private ProgressDialog progress;
private FileUtils fileUtils;
private String gpxPath;
private int gpxFileCount;
private int importSuccessCount;
public ImportAllTracks(Activity activity) {
this.activity = activity;
Log.i(MyTracksConstants.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);
}
private final Runnable runner = new Runnable() {
public void run() {
aquireLocksAndImport();
}
};
/**
* Makes sure that we keep the phone from sleeping. See if there is a current
* track. Acquire a wake lock if there is no current track.
*/
private void aquireLocksAndImport() {
SharedPreferences prefs = activity.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
long recordingTrackId = -1;
if (prefs != null) {
recordingTrackId = prefs.getLong(activity.getString(R.string.recording_track_key), -1);
}
if (recordingTrackId != -1) {
wakeLock = MyTracksUtils.acquireWakeLock(activity, wakeLock);
}
// Now we can safely import everything.
importAll();
// Release the wake lock if we acquired one.
// TODO check what happens if we started recording after getting this lock.
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
Log.i(MyTracksConstants.TAG, "ImportAllTracks: Releasing wake lock.");
}
Log.i(MyTracksConstants.TAG, "ImportAllTracks: Done");
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
if (gpxFileCount == 0) {
builder.setMessage(activity.getString(R.string.import_empty, gpxPath + "/"));
} else {
builder.setMessage(activity.getString(R.string.import_done, importSuccessCount, gpxFileCount,
gpxPath + "/"));
}
builder.setPositiveButton(R.string.ok, null);
builder.show();
}
private void makeProgressDialog(final int trackCount) {
String importMsg = activity.getString(R.string.tracklist_btn_import_all);
progress = new ProgressDialog(activity);
progress.setIcon(android.R.drawable.ic_dialog_info);
progress.setTitle(importMsg);
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setMax(trackCount);
progress.setProgress(0);
progress.show();
}
/**
* Actually import the tracks. This should be called after the wake locks have
* been acquired.
*/
private void importAll() {
MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(activity);
if (!fileUtils.isSdCardAvailable()) {
return;
}
List<File> gpxFiles = getGpxFiles();
gpxFileCount = gpxFiles.size();
if (gpxFileCount == 0) {
return;
}
Log.i(MyTracksConstants.TAG, "ImportAllTracks: Importing: " + gpxFileCount + " tracks.");
activity.runOnUiThread(new Runnable() {
public void run() {
makeProgressDialog(gpxFileCount);
}
});
Iterator<File> gpxFilesIterator = gpxFiles.iterator();
for (int currentFileNumber = 0; gpxFilesIterator.hasNext(); currentFileNumber++) {
File currentFile = gpxFilesIterator.next();
final int status = currentFileNumber;
activity.runOnUiThread(new Runnable() {
public void run() {
synchronized (this) {
if (progress == null) {
return;
}
progress.setProgress(status);
}
}
});
if (importFile(currentFile, providerUtils)) {
importSuccessCount++;
}
}
if (progress != null) {
synchronized (this) {
progress.dismiss();
progress = null;
}
}
}
/**
* Attempts to import a GPX file. Returns true on success, issues error
* notifications and returns false on failure.
*/
private boolean importFile(File gpxFile, MyTracksProviderUtils providerUtils) {
Log.i(MyTracksConstants.TAG, "ImportAllTracks: importing: " + gpxFile.getName());
try {
GpxImporter.importGPXFile(new FileInputStream(gpxFile), providerUtils);
return true;
} catch (FileNotFoundException e) {
Log.w(MyTracksConstants.TAG, "GPX file wasn't found/went missing: "
+ gpxFile.getAbsolutePath(), e);
} catch (ParserConfigurationException e) {
Log.w(MyTracksConstants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
} catch (SAXException e) {
Log.w(MyTracksConstants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
} catch (IOException e) {
Log.w(MyTracksConstants.TAG, "Error reading file: " + gpxFile.getAbsolutePath(), e);
}
Toast.makeText(activity, activity.getString(R.string.import_error, gpxFile.getName()),
Toast.LENGTH_LONG).show();
return false;
}
/**
* Returns a list of the GPX Files found in the GPX directory.
*/
private List<File> getGpxFiles() {
List<File> gpxFiles = new LinkedList<File>();
File[] gpxFileCandidates = new File(gpxPath).listFiles();
if (gpxFileCandidates != null) {
for (File file : gpxFileCandidates) {
if (!file.isDirectory() && file.getName().endsWith(".gpx")) {
gpxFiles.add(file);
}
}
}
return gpxFiles;
}
}
@@ -42,7 +42,7 @@ class MenuManager {
public void onPrepareOptionsMenu(Menu menu, boolean hasRecorded,
boolean isRecording, boolean hasSelectedTrack) {
menu.findItem(R.id.menu_list_tracks);
menu.findItem(R.id.menu_list_tracks).setEnabled(hasRecorded);
menu.findItem(R.id.menu_list_markers)
.setEnabled(hasRecorded && hasSelectedTrack);
menu.findItem(R.id.menu_start_recording)
@@ -1,210 +0,0 @@
/*
* 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 com.google.android.accounts.Account;
import com.google.android.apps.mytracks.io.AuthManager;
import com.google.android.apps.mytracks.io.AuthManagerFactory;
import com.google.android.apps.mytracks.io.MyMapsFactory;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
import com.google.android.apps.mytracks.io.mymaps.MapsService;
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.view.View;
import android.view.View.OnCreateContextMenuListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
/**
* Activity which displays the list of current My Maps tracks for the user.
* Returns RESULT_OK if the user picked a map, and returns "mapid" as an extra.
*
* @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;
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
public void onItemClick(AdapterView<?> parent, View v, int position,
long id) {
Intent result = new Intent();
result.putExtra("mapid", (String) listAdapter.getItem(position));
setResult(RESULT_OK, result);
finish();
}
};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
auth = AuthManagerFactory.getAuthManager(this, GET_LOGIN, null, true,
MapsService.getServiceName());
setContentView(R.layout.list);
listAdapter = new MyMapsListAdapter(this);
ListView list = (ListView) findViewById(R.id.maplist);
list.setOnItemClickListener(clickListener);
list.setOnCreateContextMenuListener(contextMenuListener);
list.setAdapter(listAdapter);
startLogin();
}
private void startLogin() {
// 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);
}
}
});
} else {
doLogin(null);
}
}
private void doLogin(final Account account) {
// Starts in the UI thread.
auth.doLogin(new Runnable() {
public void run() {
// Runs in UI thread.
mapsClient = MyMapsFactory.newMapsClient(MyMapsList.this, auth);
startLookup();
}
}, account);
}
private void startLookup() {
// Starts in the UI thread.
new Thread() {
@Override
public void run() {
// Communication with Maps happens in its own thread.
// This will call onReceivedMapListing below.
final boolean success = mapsClient.getMapsList(MyMapsList.this);
runOnUiThread(new Runnable() {
@Override
public void run() {
// Updating the UI when done happens in the UI thread.
onLookupDone(success);
}
});
}
}.start();
}
@Override
public void onReceivedMapListing(final String mapId, final String title,
final String description, final boolean isPublic) {
// Starts in the communication thread.
runOnUiThread(new Runnable() {
@Override
public void run() {
// Updating the list with new contents happens in the UI thread.
listAdapter.addMapListing(mapId, title, description, isPublic);
}
});
}
private void onLookupDone(boolean success) {
// Starts in the UI thread.
findViewById(R.id.loading).setVisibility(View.GONE);
if (!success) {
findViewById(R.id.failed).setVisibility(View.VISIBLE);
}
TextView emptyView = (TextView) findViewById(R.id.mapslist_empty);
ListView list = (ListView) findViewById(R.id.maplist);
list.setEmptyView(emptyView);
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == GET_LOGIN) {
auth.authResult(resultCode, data);
}
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],
MapsService.buildMapUrl(listItem[0])));
startActivity(Intent.createChooser(shareIntent,
getText(R.string.share_map).toString()));
return true;
}
return false;
}
}
@@ -1,135 +0,0 @@
package com.google.android.apps.mytracks;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.database.DataSetObserver;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.TextView;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;
public class MyMapsListAdapter implements ListAdapter {
private Vector<String[]> mapsList;
private Vector<Boolean> publicList;
private Set<DataSetObserver> observerSet;
private final Activity activity;
public MyMapsListAdapter(Activity activity) {
this.activity = activity;
mapsList = new Vector<String[]>();
publicList = new Vector<Boolean>();
observerSet = new HashSet<DataSetObserver>();
}
public void addMapListing(String mapId, String title,
String description, boolean isPublic) {
synchronized (mapsList) {
// Search through the maps list to see if it has the mapid and
// remove it if so, so that we can replace it with updated info
for (int i = 0; i < mapsList.size(); ++i) {
if (mapId.equals(mapsList.get(i)[0])) {
mapsList.remove(i);
publicList.remove(i);
--i;
}
}
mapsList.add(new String[] { mapId, title, description });
publicList.add(isPublic);
}
Iterator<DataSetObserver> iter = observerSet.iterator();
while (iter.hasNext()) {
iter.next().onChanged();
}
}
public String[] getMapListingArray(int position) {
return mapsList.get(position);
}
@Override
public boolean areAllItemsEnabled() {
return true;
}
@Override
public boolean isEnabled(int position) {
return true;
}
@Override
public int getCount() {
return mapsList.size();
}
@Override
public Object getItem(int position) {
return mapsList.get(position)[0];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView =
activity.getLayoutInflater().inflate(R.layout.listitem, parent, false);
}
String[] map = mapsList.get(position);
((TextView) convertView.findViewById(R.id.maplistitem)).setText(map[1]);
((TextView) convertView.findViewById(R.id.maplistdesc)).setText(map[2]);
TextView publicUnlisted =
(TextView) convertView.findViewById(R.id.maplistpublic);
if (publicList.get(position)) {
publicUnlisted.setTextColor(Color.RED);
publicUnlisted.setText(R.string.public_map);
} else {
publicUnlisted.setTextColor(Color.GREEN);
publicUnlisted.setText(R.string.unlisted_map);
}
return convertView;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isEmpty() {
return mapsList.isEmpty();
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
observerSet.add(observer);
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
observerSet.remove(observer);
}
}
@@ -29,17 +29,11 @@ import com.google.android.apps.mytracks.io.AuthManagerFactory;
import com.google.android.apps.mytracks.io.GpxImporter;
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.TempFileCleaner;
import com.google.android.apps.mytracks.io.TrackWriter;
import com.google.android.apps.mytracks.io.TrackWriterFactory;
import com.google.android.apps.mytracks.io.SendToFusionTables.OnSendCompletedListener;
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.io.mymaps.MapsService;
import com.google.android.apps.mytracks.io.sendtogoogle.ResultDialogFactory;
import com.google.android.apps.mytracks.io.sendtogoogle.SendDialog;
import com.google.android.apps.mytracks.io.sendtogoogle.SendResult;
import com.google.android.apps.mytracks.io.sendtogoogle.SendType;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.services.TrackRecordingService;
@@ -68,15 +62,14 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.widget.RelativeLayout;
import android.widget.TabHost;
import android.widget.Toast;
@@ -85,9 +78,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
@@ -131,11 +122,8 @@ public class MyTracks extends TabActivity implements OnTouchListener,
*/
public long sendToTrackId = -1;
public boolean sendToMyMapsSuccess = false;
public boolean sendToFusionTablesSuccess = false;
public boolean sendToDocsSuccess = false;
public String sendToMyMapsMapId;
public String sendToMyMapsMessage = "";
public String sendToFusionTablesTableId;
public String sendToFusionTablesMessage = "";
public String sendToDocsMessage = "";
@@ -158,9 +146,9 @@ public class MyTracks extends TabActivity implements OnTouchListener,
*/
private long selectedTrackId = -1;
/**
* Does the user want to share the current track.
*/
/**
* Does the user want to share the current track.
*/
private boolean shareRequested = false;
/**
@@ -458,8 +446,27 @@ public class MyTracks extends TabActivity implements OnTouchListener,
final Intent results) {
TrackFileFormat exportFormat = null;
switch (requestCode) {
case MyTracksConstants.GET_MAP: {
if (resultCode == RESULT_OK) {
results.putExtra("trackid", selectedTrackId);
if (results.hasExtra("tableid")) {
sendToFusionTablesTableId = results.getStringExtra("tableid");
}
setProgressMessage(
R.string.progress_message_authenticating_fusiontables);
authenticate(results, MyTracksConstants.SEND_TO_GOOGLE,
SendToFusionTables.SERVICE_ID);
} else {
dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
}
break;
}
case MyTracksConstants.GET_LOGIN: {
if (resultCode != RESULT_OK || auth == null || !auth.authResult(resultCode, results)) {
if (resultCode == RESULT_OK && auth != null) {
if (!auth.authResult(resultCode, results)) {
dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
}
} else {
dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
}
break;
@@ -508,78 +515,116 @@ public class MyTracks extends TabActivity implements OnTouchListener,
}
break;
}
case MyTracksConstants.SEND_TO_GOOGLE_DIALOG: {
shareRequested = false;
dialogManager.showDialogSafely(DIALOG_SEND_TO_GOOGLE);
break;
}
case MyTracksConstants.GET_MAP: {
// User picked a map to upload to
if (resultCode == RESULT_OK) {
results.putExtra("trackid", selectedTrackId);
if (results.hasExtra("mapid")) {
sendToMyMapsMapId = results.getStringExtra("mapid");
}
authenticateToGoogleMaps(results);
} else {
onSendToGoogleDone();
}
break;
}
case MyTracksConstants.AUTHENTICATE_TO_MY_MAPS: {
// Authenticated with Google My Maps
if (results != null && resultCode == RESULT_OK) {
final String mapId;
final long trackId;
if (results.hasExtra("mapid")) {
mapId = results.getStringExtra("mapid");
} else {
mapId = "new";
}
if (results.hasExtra("trackid")) {
trackId = results.getLongExtra("trackid", -1);
} else {
trackId = selectedTrackId;
}
sendToGoogleMaps(trackId, mapId);
} else {
onSendToGoogleDone();
}
break;
}
case MyTracksConstants.AUTHENTICATE_TO_FUSION_TABLES: {
// Authenticated with Google Fusion Tables
if (results != null && resultCode == RESULT_OK) {
final long trackId;
if (results.hasExtra("trackid")) {
trackId = results.getLongExtra("trackid", -1);
} else {
trackId = selectedTrackId;
}
sendToFusionTables(trackId);
} else {
onSendToGoogleDone();
}
break;
}
case MyTracksConstants.AUTHENTICATE_TO_DOCLIST: {
// Authenticated with Google Docs
if (resultCode == RESULT_OK) {
authenticateToGoogleTrix();
setProgressValue(0);
setProgressMessage(
R.string.progress_message_authenticating_docs);
authenticate(results,
MyTracksConstants.AUTHENTICATE_TO_TRIX,
SendToDocs.GDATA_SERVICE_NAME_DOCLIST);
} else {
onSendToGoogleDone();
dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
}
break;
}
case MyTracksConstants.AUTHENTICATE_TO_TRIX: {
// Authenticated with Trix
if (resultCode == RESULT_OK) {
final long trackId = results.getLongExtra("trackid", selectedTrackId);
sendToGoogleDocs(trackId);
setProgressValue(30);
setProgressMessage(
R.string.progress_message_authenticating_docs);
authenticate(results, MyTracksConstants.SEND_TO_DOCS,
SendToDocs.GDATA_SERVICE_NAME_TRIX);
} else {
onSendToGoogleDone();
dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
}
break;
}
case MyTracksConstants.SEND_TO_DOCS: {
if (results != null && resultCode == RESULT_OK) {
Log.d(MyTracksConstants.TAG, "Sending to Docs....");
setProgressValue(50);
setProgressMessage(R.string.progress_message_sending_docs);
final long trackId = results.getLongExtra("trackid", selectedTrackId);
final SendToDocs sender = new SendToDocs(this,
authMap.get(SendToDocs.GDATA_SERVICE_NAME_TRIX),
authMap.get(SendToDocs.GDATA_SERVICE_NAME_DOCLIST), trackId);
sendToTrackId = trackId;
Runnable onCompletion = new Runnable() {
public void run() {
setProgressValue(100);
dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
runOnUiThread(new Runnable() {
public void run() {
sendToDocsMessage = sender.getStatusMessage();
sendToDocsSuccess = sender.wasSuccess();
handleFusionTablesFinish(trackId);
}
});
}
};
sender.setOnCompletion(onCompletion);
sender.run();
} else {
dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
}
break;
}
case MyTracksConstants.SEND_TO_GOOGLE_DIALOG: {
shareRequested = false;
dialogManager.showDialogSafely(DIALOG_SEND_TO_GOOGLE);
break;
}
case MyTracksConstants.SEND_TO_GOOGLE: {
if (results != null && resultCode == RESULT_OK) {
final long trackId;
if (results.hasExtra("trackid")) {
trackId = results.getLongExtra("trackid", -1);
} else {
trackId = selectedTrackId;
}
OnSendCompletedListener onCompletion = new OnSendCompletedListener() {
@Override
public void onSendCompleted(String tableId, boolean success,
int statusMessage) {
sendToFusionTablesMessage = getString(statusMessage);
sendToFusionTablesSuccess = success;
if (sendToFusionTablesSuccess) {
sendToFusionTablesTableId = tableId;
// Update the table id for this track:
try {
Track track = providerUtils.getTrack(trackId);
track.setTableId(tableId);
providerUtils.updateTrack(track);
} catch (RuntimeException e) {
// If that fails whatever reasons we'll just log an error, but
// continue.
Log.w(MyTracksConstants.TAG, "Updating table id failed.", e);
}
}
if (dialogManager.getSendToGoogleDialog().getSendToDocs()) {
onActivityResult(MyTracksConstants.AUTHENTICATE_TO_DOCLIST,
RESULT_OK, new Intent());
} else {
dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
runOnUiThread(new Runnable() {
public void run() {
handleFusionTablesFinish(trackId);
}
});
}
}
};
sendToTrackId = trackId;
final SendToFusionTables sender = new SendToFusionTables(this, auth,
trackId, this/*progressIndicator*/, onCompletion);
HandlerThread handlerThread = new HandlerThread("SendToFusionTables");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
handler.post(sender);
} else {
dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
}
break;
}
@@ -605,10 +650,8 @@ public class MyTracks extends TabActivity implements OnTouchListener,
case MyTracksConstants.SHARE_LINK: {
Track selectedTrack = providerUtils.getTrack(selectedTrackId);
if (selectedTrack != null) {
if (!TextUtils.isEmpty(selectedTrack.getMapId())) {
shareLinkToMap(MapsService.buildMapUrl(selectedTrack.getMapId()));
} else if (!TextUtils.isEmpty(selectedTrack.getTableId())) {
shareLinkToMap(getFusionTablesUrl(selectedTrackId));
if (selectedTrack.getTableId().length() > 0) {
shareLinkToFusionTable(selectedTrackId);
} else {
shareRequested = true;
dialogManager.showDialogSafely(DIALOG_SEND_TO_GOOGLE);
@@ -677,9 +720,6 @@ public class MyTracks extends TabActivity implements OnTouchListener,
* Resets status information for sending to MyMaps/Docs.
*/
public void resetSendToGoogleStatus() {
sendToMyMapsMapId = null;
sendToMyMapsMessage = "";
sendToMyMapsSuccess = true;
sendToFusionTablesMessage = "";
sendToFusionTablesSuccess = true;
sendToDocsMessage = "";
@@ -752,10 +792,10 @@ public class MyTracks extends TabActivity implements OnTouchListener,
}
/**
* Shares a link to a My Map or Fusion Table via external app (email, gmail, ...)
* Shares a link to a fusion table via external app (email, gmail, ...)
* A chooser with apps that support text/plain will be shown to the user.
*/
public void shareLinkToMap(String url) {
public void shareLinkToFusionTable(long trackId) {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
@@ -767,6 +807,8 @@ public class MyTracks extends TabActivity implements OnTouchListener,
getString(R.string.share_url_only_key), false);
}
Track track = providerUtils.getTrack(trackId);
String url = SendToFusionTables.getMapVisualizationUrl(track);
String msg = shareUrlOnly ? url : String.format(
getResources().getText(R.string.share_map_body_format).toString(), url);
shareIntent.putExtra(Intent.EXTRA_TEXT, msg);
@@ -985,11 +1027,9 @@ public class MyTracks extends TabActivity implements OnTouchListener,
* Initiates the process to send tracks to google.
* This is called once the user has selected sending options via the
* SendToGoogleDialog.
*
* TODO: Change this whole flow to an actual state machine.
*/
public void sendToGoogle() {
SendDialog sendToGoogleDialog =
SendToGoogleDialog sendToGoogleDialog =
dialogManager.getSendToGoogleDialog();
if (sendToGoogleDialog == null) {
return;
@@ -997,273 +1037,17 @@ public class MyTracks extends TabActivity implements OnTouchListener,
setProgressValue(0);
clearProgressMessage();
dialogManager.showDialogSafely(DIALOG_PROGRESS);
if (sendToGoogleDialog.getSendToMyMaps()) {
sendToGoogleMapsOrPickMap(sendToGoogleDialog);
} else if (sendToGoogleDialog.getSendToFusionTables()) {
authenticateToFusionTables(null);
} else if (sendToGoogleDialog.getSendToDocs()) {
authenticateToGoogleDocs();
} else {
Log.w(MyTracksConstants.TAG, "Nowhere to upload to");
onSendToGoogleDone();
}
}
private void sendToGoogleMapsOrPickMap(SendDialog sendToGoogleDialog) {
if (!sendToGoogleDialog.getCreateNewMap()) {
// Ask the user to choose a map to upload into
Intent listIntent = new Intent(this, MyMapsList.class);
startActivityForResult(listIntent, MyTracksConstants.GET_MAP);
// The callback for GET_MAP calls authenticateToGoogleMaps
} else {
authenticateToGoogleMaps(null);
}
}
private void authenticateToGoogleMaps(Intent results) {
if (results == null) { results = new Intent(); }
setProgressValue(0);
setProgressMessage(
R.string.progress_message_authenticating_mymaps);
authenticate(results, MyTracksConstants.AUTHENTICATE_TO_MY_MAPS,
MapsService.getServiceName());
// AUTHENTICATE_TO_MY_MAPS callback calls sendToGoogleMaps
}
private void sendToGoogleMaps(final long trackId, String mapId) {
SendToMyMaps.OnSendCompletedListener onCompletion = new SendToMyMaps.OnSendCompletedListener() {
@Override
public void onSendCompleted(String mapId, boolean success, int statusMessage) {
sendToMyMapsMessage = getString(statusMessage);
sendToMyMapsSuccess = success;
if (sendToMyMapsSuccess) {
sendToMyMapsMapId = mapId;
// Update the map id for this track:
try {
Track track = providerUtils.getTrack(trackId);
track.setMapId(mapId);
providerUtils.updateTrack(track);
} catch (RuntimeException e) {
// If that fails whatever reasons we'll just log an error, but
// continue.
Log.w(MyTracksConstants.TAG, "Updating map id failed.", e);
}
}
onSendToGoogleMapsDone();
}
};
final SendToMyMaps sender = new SendToMyMaps(this, mapId, auth,
trackId, this /*progressIndicator*/, onCompletion);
HandlerThread handlerThread = new HandlerThread("SendToMyMaps");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
handler.post(sender);
}
private void onSendToGoogleMapsDone() {
SendDialog sendToGoogleDialog = dialogManager.getSendToGoogleDialog();
if (sendToGoogleDialog.getSendToFusionTables()) {
authenticateToFusionTables(null);
} else if (sendToGoogleDialog.getSendToDocs()) {
authenticateToGoogleDocs();
setProgressValue(0);
setProgressMessage(R.string.progress_message_authenticating_fusiontables);
authenticate(new Intent(), MyTracksConstants.SEND_TO_GOOGLE,
SendToFusionTables.SERVICE_ID);
} else {
onSendToGoogleDone();
onActivityResult(MyTracksConstants.AUTHENTICATE_TO_DOCLIST, RESULT_OK,
new Intent());
}
}
private void authenticateToFusionTables(Intent results) {
if (results == null) { results = new Intent(); }
setProgressValue(0);
setProgressMessage(R.string.progress_message_authenticating_fusiontables);
authenticate(results, MyTracksConstants.AUTHENTICATE_TO_FUSION_TABLES,
SendToFusionTables.SERVICE_ID);
// AUTHENTICATE_TO_FUSION_TABLES callback calls sendToFusionTables
}
private void sendToFusionTables(final long trackId) {
OnSendCompletedListener onCompletion = new OnSendCompletedListener() {
@Override
public void onSendCompleted(String tableId, boolean success,
int statusMessage) {
sendToFusionTablesMessage = getString(statusMessage);
sendToFusionTablesSuccess = success;
if (sendToFusionTablesSuccess) {
sendToFusionTablesTableId = tableId;
// Update the table id for this track:
try {
Track track = providerUtils.getTrack(trackId);
track.setTableId(tableId);
providerUtils.updateTrack(track);
} catch (RuntimeException e) {
// If that fails whatever reasons we'll just log an error, but
// continue.
Log.w(MyTracksConstants.TAG, "Updating table id failed.", e);
}
}
onSendToFusionTablesDone();
}
};
sendToTrackId = trackId;
final SendToFusionTables sender = new SendToFusionTables(this, auth,
trackId, this/*progressIndicator*/, onCompletion);
HandlerThread handlerThread = new HandlerThread("SendToFusionTables");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
handler.post(sender);
}
private void onSendToFusionTablesDone() {
SendDialog sendToGoogleDialog = dialogManager.getSendToGoogleDialog();
if (sendToGoogleDialog.getSendToDocs()) {
authenticateToGoogleDocs();
} else {
onSendToGoogleDone();
}
}
private void authenticateToGoogleDocs() {
setProgressValue(0);
setProgressMessage(
R.string.progress_message_authenticating_docs);
authenticate(new Intent(),
MyTracksConstants.AUTHENTICATE_TO_DOCLIST,
SendToDocs.GDATA_SERVICE_NAME_DOCLIST);
// AUTHENTICATE_TO_DOCLIST callback calls authenticateToGoogleTrix
}
private void authenticateToGoogleTrix() {
setProgressValue(30);
setProgressMessage(
R.string.progress_message_authenticating_docs);
authenticate(new Intent(),
MyTracksConstants.AUTHENTICATE_TO_TRIX,
SendToDocs.GDATA_SERVICE_NAME_TRIX);
// AUTHENTICATE_TO_TRIX callback calls sendToGoogleDocs
}
private void sendToGoogleDocs(final long trackId) {
Log.d(MyTracksConstants.TAG, "Sending to 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), trackId);
sendToTrackId = trackId;
Runnable onCompletion = new Runnable() {
public void run() {
setProgressValue(100);
dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
sendToDocsMessage = sender.getStatusMessage();
sendToDocsSuccess = sender.wasSuccess();
onSendToGoogleDocsDone();
}
};
sender.setOnCompletion(onCompletion);
sender.run();
}
private void onSendToGoogleDocsDone() {
onSendToGoogleDone();
}
private void onSendToGoogleDone() {
SendDialog sendToGoogleDialog = dialogManager.getSendToGoogleDialog();
final boolean sentToMyMaps = sendToGoogleDialog.getSendToMyMaps();
final boolean sentToFusionTables = sendToGoogleDialog.getSendToFusionTables();
dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
// 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.
final boolean canShare = getSendToFusionTablesTableId() != null
|| getSendToMyMapsMapId() != null;
DialogInterface.OnClickListener doShareListener = null;
if (canShare) {
doShareListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
shareLinkToMap(sentToMyMaps, sentToFusionTables);
}
};
}
DialogInterface.OnClickListener onOkListener = (canShare && shareRequested)
? doShareListener : null;
DialogInterface.OnClickListener onShareListener = (canShare && !shareRequested)
? doShareListener : null;
AlertDialog sendToGoogleResultDialog = ResultDialogFactory.makeDialog(this,
makeSendToGoogleResults(sendToGoogleDialog), onOkListener, onShareListener);
DialogManager.showDialogSafely(this, sendToGoogleResultDialog);
}
private boolean shareLinkToMap(boolean sentToMyMaps, boolean sentToFusionTables) {
String url = null;
if (sentToMyMaps && sendToMyMapsSuccess) {
// Prefer a link to My Maps
url = MapsService.buildMapUrl(sendToMyMapsMapId);
} else if (sentToFusionTables && sendToFusionTablesSuccess) {
// Otherwise try using the link to fusion tables
url = getFusionTablesUrl(sendToTrackId);
}
if (url != null) {
shareLinkToMap(url);
return true;
}
return false;
}
protected String getFusionTablesUrl(long sendToTrackId2) {
Track track = providerUtils.getTrack(sendToTrackId);
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(SendDialog dialog) {
List<SendResult> results = new ArrayList<SendResult>();
if (dialog.getSendToMyMaps()) {
results.add(new SendResult(SendType.MYMAPS, sendToMyMapsSuccess));
}
if (dialog.getSendToFusionTables()) {
results.add(new SendResult(SendType.FUSION_TABLES, sendToFusionTablesSuccess));
}
if (dialog.getSendToDocs()) {
results.add(new SendResult(SendType.DOCS, sendToDocsSuccess));
}
return results;
}
/**
* Writes the selected track id to the shared preferences.
* Executed on the UI thread.
@@ -1373,6 +1157,35 @@ public class MyTracks extends TabActivity implements OnTouchListener,
writer.writeTrackAsync();
}
/**
* Notifies that uploading to fusion tables is finished.
*/
private void handleFusionTablesFinish(long trackId) {
if (shareRequested && sendToFusionTablesSuccess) {
// Just share
Toast.makeText(this, getFusionTablesResultMessage(), Toast.LENGTH_LONG).show();
shareLinkToFusionTable(trackId);
} else {
dialogManager.showDialogSafely(DialogManager.DIALOG_SEND_TO_GOOGLE_RESULT);
}
}
public String getFusionTablesResultMessage() {
StringBuilder message = new StringBuilder();
SendToGoogleDialog sendToGoogleDialog =
dialogManager.getSendToGoogleDialog();
if (sendToGoogleDialog.getSendToFusionTables()) {
message.append(sendToFusionTablesMessage);
}
if (sendToGoogleDialog.getSendToDocs()) {
if (message.length() > 0) {
message.append(' ');
}
message.append(sendToDocsMessage);
}
return message.toString();
}
public AccountChooser getAccountChooser() {
return accountChooser;
}
@@ -1389,33 +1202,29 @@ public class MyTracks extends TabActivity implements OnTouchListener,
return dialogManager;
}
public String getSendToMyMapsMapId() {
return sendToMyMapsMapId;
}
public String getSendToFusionTablesTableId() {
return sendToFusionTablesTableId;
}
public boolean getSendToGoogleSuccess() {
return sendToMyMapsSuccess && sendToFusionTablesSuccess && sendToDocsSuccess;
return sendToFusionTablesSuccess && sendToDocsSuccess;
}
// @VisibleForTesting
long getRecordingTrackId() {
return recordingTrackId;
}
// @VisibleForTesting
SharedPreferences getSharedPreferences() {
return sharedPreferences;
}
// @VisibleForTesting
static void clearInstance() {
instance = null;
}
// @VisibleForTesting
ITrackRecordingService getTrackRecordingService() {
return trackRecordingService;
@@ -50,26 +50,26 @@ public abstract class MyTracksConstants {
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 AUTHENTICATE_TO_DOCLIST = 8;
public static final int AUTHENTICATE_TO_TRIX = 9;
public static final int SEND_TO_DOCS = 10;
public static final int DELETE_TRACK = 11;
public static final int SEND_TO_GOOGLE = 12;
public static final int SEND_TO_GOOGLE_DIALOG = 13;
public static final int SHARE_LINK = 14;
public static final int SHARE_GPX_FILE = 15;
public static final int SHARE_KML_FILE = 16;
public static final int SHARE_CSV_FILE = 17;
public static final int SHARE_TCX_FILE = 18;
public static final int EDIT_DETAILS = 19;
public static final int SAVE_GPX_FILE = 20;
public static final int SAVE_KML_FILE = 21;
public static final int SAVE_CSV_FILE = 22;
public static final int SAVE_TCX_FILE = 23;
public static final int CLEAR_MAP = 24;
public static final int SHOW_WAYPOINT = 25;
public static final int EDIT_WAYPOINT = 26;
public static final int WELCOME = 27;
/*
* Menu ids:
@@ -83,7 +83,7 @@ public class MyTracksList extends ListActivity
SubMenu share = menu.addSubMenu(0, MyTracksConstants.MENU_SHARE, 0,
R.string.tracklist_share_track);
share.add(0, MyTracksConstants.MENU_SHARE_LINK, 0,
R.string.tracklist_share_link);
R.string.tracklist_share_linkfusion);
share.add(0, MyTracksConstants.MENU_SHARE_GPX_FILE, 0,
R.string.tracklist_share_gpx_file);
share.add(0, MyTracksConstants.MENU_SHARE_KML_FILE, 0,
@@ -178,10 +178,6 @@ public class MyTracksList extends ListActivity
new ExportAllTracks(this);
break;
}
case R.id.tracklist_btn_import_all: {
new ImportAllTracks(this);
break;
}
}
}
@@ -199,7 +195,6 @@ public class MyTracksList extends ListActivity
findViewById(R.id.tracklist_btn_delete_all).setOnClickListener(this);
findViewById(R.id.tracklist_btn_export_all).setOnClickListener(this);
findViewById(R.id.tracklist_btn_import_all).setOnClickListener(this);
SharedPreferences preferences =
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
@@ -201,10 +201,7 @@ public class MyTracksMap extends MapActivity
MyTracksConstants.MAX_DISPLAYED_WAYPOINTS_POINTS);
if (cursor != null && cursor.moveToFirst()) {
do {
Waypoint waypoint = providerUtils.createWaypoint(cursor);
if (MyTracksUtils.isValidLocation(waypoint.getLocation())) {
mapOverlay.addWaypoint(waypoint);
}
mapOverlay.addWaypoint(providerUtils.createWaypoint(cursor));
} while (cursor.moveToNext());
}
} catch (RuntimeException e) {
@@ -792,7 +789,7 @@ public class MyTracksMap extends MapActivity
SubMenu share = menu.addSubMenu(0, MyTracksConstants.MENU_SHARE, 0,
R.string.tracklist_share_track);
share.add(0, MyTracksConstants.MENU_SHARE_LINK, 0,
R.string.tracklist_share_link);
R.string.tracklist_share_linkfusion);
share.add(0, MyTracksConstants.MENU_SHARE_GPX_FILE, 0,
R.string.tracklist_share_gpx_file);
share.add(0, MyTracksConstants.MENU_SHARE_KML_FILE, 0,
@@ -16,14 +16,11 @@
package com.google.android.apps.mytracks;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.android.apps.mytracks.io.backup.BackupActivityHelper;
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.services.sensors.ant.AntUtils;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
import com.google.android.maps.mytracks.R;
@@ -38,7 +35,6 @@ import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceScreen;
import android.provider.Settings;
/**
@@ -107,21 +103,6 @@ public class MyTracksSettings extends PreferenceActivity {
});
updatePreferenceUnits(metricUnitsPreference.isChecked());
customizeSensorOptionsPreferences();
// Disable TTS announcement preference if not available
if (!apiFeatures.hasTextToSpeech()) {
IntegerListPreference announcementFrequency =
(IntegerListPreference) findPreference(
getString(R.string.announcement_frequency_key));
announcementFrequency.setEnabled(false);
announcementFrequency.setValue("-1");
announcementFrequency.setSummary(
R.string.settings_not_available_summary);
}
}
private void customizeSensorOptionsPreferences() {
ListPreference sensorTypePreference =
(ListPreference) findPreference(getString(R.string.sensor_type_key));
sensorTypePreference.setOnPreferenceChangeListener(
@@ -134,37 +115,16 @@ public class MyTracksSettings extends PreferenceActivity {
}
});
updateSensorSettings(sensorTypePreference.getValue());
if (!AntUtils.hasAntSupport(this)) {
// The sensor options screen has a few ANT-specific options which we
// need to remove. First, we need to remove the ANT sensor types.
// Second, we need to remove the ANT unpairing options.
Set<Integer> toRemove = new HashSet<Integer>();
String[] antValues = getResources().getStringArray(R.array.ant_sensor_type_values);
for (String antValue : antValues) {
toRemove.add(sensorTypePreference.findIndexOfValue(antValue));
}
CharSequence[] entries = sensorTypePreference.getEntries();
CharSequence[] entryValues = sensorTypePreference.getEntryValues();
CharSequence[] filteredEntries = new CharSequence[entries.length - toRemove.size()];
CharSequence[] filteredEntryValues = new CharSequence[filteredEntries.length];
for (int i = 0, last = 0; i < entries.length; i++) {
if (!toRemove.contains(i)) {
filteredEntries[last] = entries[i];
filteredEntryValues[last++] = entryValues[i];
}
}
sensorTypePreference.setEntries(filteredEntries);
sensorTypePreference.setEntryValues(filteredEntryValues);
PreferenceScreen sensorOptionsScreen =
(PreferenceScreen) findPreference(getString(R.string.sensor_options_key));
sensorOptionsScreen.removePreference(findPreference(getString(R.string.ant_options_key)));
// Disable TTS announcement preference if not available
if (!apiFeatures.hasTextToSpeech()) {
IntegerListPreference announcementFrequency =
(IntegerListPreference) findPreference(
getString(R.string.announcement_frequency_key));
announcementFrequency.setEnabled(false);
announcementFrequency.setValue("-1");
announcementFrequency.setSummary(
R.string.settings_not_available_summary);
}
}
@@ -232,14 +192,10 @@ public class MyTracksSettings extends PreferenceActivity {
// Update the ANT+ sensors.
// TODO: Only enable on phones that have ANT+.
Preference antHrm = findPreference(getString(R.string.ant_heart_rate_sensor_id_key));
Preference antSrm = findPreference(getString(R.string.ant_srm_bridge_sensor_id_key));
if (antHrm != null && antSrm != null) {
antHrm
.setEnabled(getString(R.string.ant_sensor_type).equals(sensorType));
antSrm
.setEnabled(getString(R.string.srm_ant_bridge_sensor_type).equals(sensorType));
}
findPreference(getString(R.string.ant_heart_rate_sensor_id_key))
.setEnabled(getString(R.string.ant_sensor_type).equals(sensorType));
findPreference(getString(R.string.ant_srm_bridge_sensor_id_key))
.setEnabled(getString(R.string.srm_ant_bridge_sensor_type).equals(sensorType));
}
/**
@@ -261,7 +217,7 @@ public class MyTracksSettings extends PreferenceActivity {
final ListPreference splitFrequency =
(ListPreference) findPreference(
getString(R.string.split_frequency_key));
minRecordingDistance.setEntries(isMetric
? R.array.min_recording_distance_options
: R.array.min_recording_distance_options_ft);
@@ -1,23 +1,20 @@
/*
* 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
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.sendtogoogle;
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.DialogManager;
import com.google.android.apps.mytracks.MyTracks;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.maps.mytracks.R;
import android.app.Dialog;
@@ -32,7 +29,6 @@ import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.RadioButton;
import android.widget.RadioGroup;
/**
* A dialog where the user can choose where to send the tracks to, i.e.
@@ -40,19 +36,15 @@ import android.widget.RadioGroup;
*
* @author Leif Hendrik Wilden
*/
public class SendDialog extends Dialog {
public class SendToGoogleDialog 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;
public SendDialog(Context context) {
public SendToGoogleDialog(Context context) {
super(context);
}
@@ -80,27 +72,19 @@ public class SendDialog extends Dialog {
OnCheckedChangeListener checkBoxListener = new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton button, boolean checked) {
sendButton.setEnabled(
sendToMyMapsCheckBox.isChecked() ||
sendToFusionTablesCheckBox.isChecked() ||
sendToDocsCheckBox.isChecked());
groupMyMaps.setVisibility(sendToMyMapsCheckBox.isChecked() ? View.VISIBLE : View.INVISIBLE);
//groupDocs.setVisibility(
// sendToDocsCheckBox.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(
@@ -109,21 +93,12 @@ public class SendDialog extends Dialog {
SharedPreferences prefs =
getContext().getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
if (prefs != null) {
sendToMyMapsCheckBox.setChecked(
prefs.getBoolean(
getContext().getString(R.string.send_to_my_maps_key), true));
sendToFusionTablesCheckBox.setChecked(
prefs.getBoolean(
getContext().getString(R.string.send_to_fusion_tables_key), true));
getContext().getString(R.string.send_to_my_maps_key), true));
sendToDocsCheckBox.setChecked(
prefs.getBoolean(
getContext().getString(R.string.send_to_docs_key), true));
pickMapRadioButton.setChecked(
prefs.getBoolean(
getContext().getString(R.string.pick_existing_map_key), false));
createNewMapRadioButton.setChecked(
!prefs.getBoolean(
getContext().getString(R.string.pick_existing_map_key), false));
sendStatsAndPointsRadioButton.setChecked(
prefs.getBoolean(
getContext().getString(R.string.send_stats_and_points_key),
@@ -144,16 +119,10 @@ public class SendDialog extends Dialog {
if (editor != null) {
editor.putBoolean(
getContext().getString(R.string.send_to_my_maps_key),
sendToMyMapsCheckBox.isChecked());
editor.putBoolean(
getContext().getString(R.string.send_to_fusion_tables_key),
sendToFusionTablesCheckBox.isChecked());
editor.putBoolean(
getContext().getString(R.string.send_to_docs_key),
sendToDocsCheckBox.isChecked());
editor.putBoolean(
getContext().getString(R.string.pick_existing_map_key),
pickMapRadioButton.isChecked());
editor.putBoolean(
getContext().getString(R.string.send_stats_and_points_key),
sendStatsAndPointsRadioButton.isChecked());
@@ -163,10 +132,6 @@ public class SendDialog extends Dialog {
super.onStop();
}
public boolean getSendToMyMaps() {
return sendToMyMapsCheckBox.isChecked();
}
public boolean getSendToFusionTables() {
return sendToFusionTablesCheckBox.isChecked();
}
@@ -175,10 +140,6 @@ public class SendDialog extends Dialog {
return sendToDocsCheckBox.isChecked();
}
public boolean getCreateNewMap() {
return createNewMapRadioButton.isChecked();
}
public boolean getSendStatsAndPoints() {
return sendStatsAndPointsRadioButton.isChecked();
}
@@ -16,7 +16,6 @@
package com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.util.ApiFeatures;
import android.content.ContentProvider;
import android.content.ContentUris;
@@ -372,11 +371,8 @@ public class MyTracksProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URL " + url);
}
if (ApiFeatures.getInstance().canReuseSQLiteQueryBuilder()) {
Log.i(MyTracksConstants.TAG,
"Build query: " + qb.buildQuery(projection, selection, selectionArgs,
null, null, sortOrder, null));
}
Log.i(MyTracksConstants.TAG,
"Build query: " + qb.buildQuery(projection, selection, selectionArgs, null, null, sortOrder, null));
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null,
sortOrder);
c.setNotificationUri(getContext().getContentResolver(), url);
@@ -23,7 +23,6 @@ import android.location.Location;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
@@ -45,13 +44,9 @@ import java.util.TimeZone;
* @author Rodrigo Damazio
*/
public class CsvTrackWriter implements TrackFormatWriter {
static final NumberFormat SHORT_FORMAT = NumberFormat.getInstance();
static final SimpleDateFormat TIMESTAMP_FORMAT =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
static {
SHORT_FORMAT.setMaximumFractionDigits(4);
TIMESTAMP_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
}
@@ -99,8 +94,8 @@ public class CsvTrackWriter implements TrackFormatWriter {
Double.toString(location.getLongitude()),
Double.toString(location.getAltitude()),
Double.toString(location.getBearing()),
SHORT_FORMAT.format(location.getAccuracy()),
SHORT_FORMAT.format(location.getSpeed()),
Double.toString(location.getAccuracy()),
Double.toString(location.getSpeed()),
null, null,
Integer.toString(segmentIdx));
}
@@ -115,8 +110,8 @@ public class CsvTrackWriter implements TrackFormatWriter {
Double.toString(location.getLongitude()),
Double.toString(location.getAltitude()),
Double.toString(location.getBearing()),
SHORT_FORMAT.format(location.getAccuracy()),
SHORT_FORMAT.format(location.getSpeed()),
Double.toString(location.getAccuracy()),
Double.toString(location.getSpeed()),
waypoint.getName(),
waypoint.getDescription(),
null);
@@ -229,10 +229,7 @@ public class GpxImporter extends DefaultHandler {
@Override
public void endElement(String uri, String localName, String name)
throws SAXException {
if (!isInTrackElement) {
content = null;
return;
}
if (!isInTrackElement) { return; }
// process these elements only as sub-elements of track
if (localName.equals(TAG_TRACK_POINT)) {
@@ -363,10 +360,6 @@ public class GpxImporter extends DefaultHandler {
*/
private void onTrackPointElementEnd() throws SAXException {
if (MyTracksUtils.isValidLocation(location)) {
if (statsBuilder == null) {
// first point did not have a time, start stats builder without it
statsBuilder = new TripStatisticsBuilder(0);
}
statsBuilder.addLocation(location, location.getTime());
// insert in db
@@ -462,18 +455,18 @@ public class GpxImporter extends DefaultHandler {
// check for negative time change
if (timeDifference < 0) {
Log.w(MyTracksConstants.TAG, "Found negative time change.");
} else {
// We don't have a speed and bearing in GPX, make something up from
// the last two points.
// TODO GPS points tend to have some inherent imprecision,
// speed and bearing will likely be off, so the statistics for things like
// max speed will also be off.
float speed = location.distanceTo(lastLocation) * 1000.0f / timeDifference;
location.setSpeed(speed);
location.setBearing(lastSegmentLocation.bearingTo(location));
String msg = createErrorMessage("Found negative time change.");
throw new SAXException(msg);
}
// We don't have a speed and bearing in GPX, make something up from
// the last two points.
// TODO GPS points tend to have some inherent imprecision,
// speed and bearing will likely be off, so the statistics for things like
// max speed will also be off.
float speed = location.distanceTo(lastLocation) * 1000.0f / timeDifference;
location.setSpeed(speed);
location.setBearing(lastSegmentLocation.bearingTo(location));
}
// Fill in the time
@@ -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
@@ -25,10 +25,8 @@ import android.location.Location;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
@@ -37,35 +35,16 @@ import java.util.TimeZone;
* @author Sandor Dornbush
*/
public class GpxTrackWriter implements TrackFormatWriter {
private static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private final NumberFormat elevationFormatter;
private final NumberFormat coordinateFormatter;
private final SimpleDateFormat timestampFormatter;
static final SimpleDateFormat TIMESTAMP_FORMAT =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
static {
TIMESTAMP_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
}
private PrintWriter pw = null;
private Track track;
public GpxTrackWriter() {
// GPX readers expect to see fractional numbers with US-style punctuation.
// That is, they want periods for decimal points, rather than commas.
elevationFormatter = NumberFormat.getInstance(Locale.US);
elevationFormatter.setMaximumFractionDigits(1);
elevationFormatter.setGroupingUsed(false);
coordinateFormatter = NumberFormat.getInstance(Locale.US);
coordinateFormatter.setMaximumFractionDigits(5);
coordinateFormatter.setMaximumIntegerDigits(3);
coordinateFormatter.setGroupingUsed(false);
timestampFormatter = new SimpleDateFormat(TIMESTAMP_FORMAT);
timestampFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
}
private String formatLocation(Location l) {
return "lat=\"" + coordinateFormatter.format(l.getLatitude())
+ "\" lon=\"" + coordinateFormatter.format(l.getLongitude()) + "\"";
}
@Override
public void prepare(Track track, OutputStream out) {
this.track = track;
@@ -84,14 +63,14 @@ public class GpxTrackWriter implements TrackFormatWriter {
Charset.defaultCharset().name());
pw.println("<?xml-stylesheet type=\"text/xsl\" href=\"details.xsl\"?>");
pw.println("<gpx");
pw.println(" version=\"1.1\"");
pw.println(" version=\"1.0\"");
pw.println(" creator=\"My Tracks for the G1 running Android\"");
pw.println(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
pw.println(" xmlns=\"http://www.topografix.com/GPX/1/1\"");
pw.println(" xmlns=\"http://www.topografix.com/GPX/1/0\"");
pw.print(" xmlns:topografix=\"http://www.topografix.com/GPX/Private/"
+ "TopoGrafix/0/1\"");
pw.print(" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 ");
pw.print("http://www.topografix.com/GPX/1/1/gpx.xsd ");
pw.print(" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 ");
pw.print("http://www.topografix.com/GPX/1/0/gpx.xsd ");
pw.print("http://www.topografix.com/GPX/Private/TopoGrafix/0/1 ");
pw.println("http://www.topografix.com/GPX/Private/TopoGrafix/0/1/"
+ "topografix.xsd\">");
@@ -115,7 +94,7 @@ public class GpxTrackWriter implements TrackFormatWriter {
pw.println("<desc>" + StringUtils.stringAsCData(track.getDescription())
+ "</desc>");
pw.println("<number>" + track.getId() + "</number>");
pw.println("<extensions><topografix:color>c0c0c0</topografix:color></extensions>");
pw.println("<topografix:color>c0c0c0</topografix:color>");
}
}
@@ -139,10 +118,11 @@ public class GpxTrackWriter implements TrackFormatWriter {
@Override
public void writeLocation(Location l) {
if (pw != null) {
pw.println("<trkpt " + formatLocation(l) + ">");
pw.println("<trkpt lat=\"" + l.getLatitude() + "\" lon=\""
+ l.getLongitude() + "\">");
Date d = new Date(l.getTime());
pw.println("<ele>" + elevationFormatter.format(l.getAltitude()) + "</ele>");
pw.println("<time>" + timestampFormatter.format(d) + "</time>");
pw.println("<ele>" + l.getAltitude() + "</ele>");
pw.println("<time>" + TIMESTAMP_FORMAT.format(d) + "</time>");
pw.println("</trkpt>");
}
}
@@ -158,15 +138,17 @@ public class GpxTrackWriter implements TrackFormatWriter {
@Override
public void writeWaypoint(Waypoint waypoint) {
if (pw != null) {
// TODO: The gpx spec says waypoints should come *before* tracks
Location l = waypoint.getLocation();
if (l != null) {
pw.println("<wpt " + formatLocation(l) + ">");
pw.println("<ele>" + elevationFormatter.format(l.getAltitude()) + "</ele>");
pw.println("<time>" + timestampFormatter.format(l.getTime()) + "</time>");
pw.println("<wpt lat=\"" + l.getLatitude() + "\" lon=\""
+ l.getLongitude() + "\">");
pw.println("<name>" + StringUtils.stringAsCData(waypoint.getName())
+ "</name>");
pw.println("<desc>"
+ StringUtils.stringAsCData(waypoint.getDescription()) + "</desc>");
pw.println("<time>" + TIMESTAMP_FORMAT.format(l.getTime()) + "</time>");
pw.println("<ele>" + l.getAltitude() + "</ele>");
pw.println("</wpt>");
}
}
@@ -1,68 +0,0 @@
package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
import com.google.android.apps.mytracks.io.mymaps.MapsService;
import com.google.android.apps.mytracks.io.mymaps.MapsStringsProvider;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade.AuthenticationRefresher;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.content.Context;
/**
* Factory to easily instantiate a {@link MapsFacade}.
*
* @author Rodrigo Damazio
*/
public class MyMapsFactory {
/**
* Simple provider for reading strings from resources.
*/
private static class MyMapsStringProvider implements MapsStringsProvider {
private final Context context;
public MyMapsStringProvider(Context context) {
this.context = context;
}
@Override
public String getNewMapDescription() {
return context.getString(R.string.new_map_description);
}
@Override
public String getStart() {
return context.getString(R.string.start);
}
@Override
public String getEnd() {
return context.getString(R.string.end);
}
}
/**
* Creates a new Maps fa�ade interface instance.
*
* @param context current context
* @param auth a valid authentication manager
* @return the fa�ade
*/
public static MapsFacade newMapsClient(Activity context, final AuthManager auth) {
MapsFacade client = MapsService.newClient(context,
GDataClientFactory.getGDataClient(context),
new MyMapsStringProvider(context),
auth.getAuthToken());
client.setAuthenticationRefresher(new AuthenticationRefresher() {
@Override
public void invalidateAndRefresh(Runnable done) {
auth.invalidateAndRefresh(done);
}
});
return client;
}
private MyMapsFactory() {}
}
@@ -28,7 +28,7 @@ import com.google.android.maps.mytracks.R;
import com.google.wireless.gdata.client.GDataClient;
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.maps.xml.XmlMapsGDataParserFactory;
import com.google.wireless.gdata.client.GDataServiceClient;
import android.app.Activity;
@@ -99,7 +99,6 @@ public class SendToDocs {
}
private void doUpload() {
// TODO
statusMessage = activity.getString(R.string.error_sending_to_fusiontables);
success = false;
@@ -174,7 +173,7 @@ public class SendToDocs {
try {
androidClient = GDataClientFactory.getGDataClient(activity);
SpreadsheetsClient gdataClient = new SpreadsheetsClient(androidClient,
new XmlDocsGDataParserFactory(new AndroidXmlParserFactory()));
new XmlMapsGDataParserFactory(new AndroidXmlParserFactory()));
trixWrapper.setClient(gdataClient);
Log.d(MyTracksConstants.TAG,
"GData connection prepared: " + this.docListAuth);
@@ -185,7 +184,7 @@ public class SendToDocs {
}
DocumentsClient docsGdataClient = new DocumentsClient(androidClient,
new XmlDocsGDataParserFactory(new AndroidXmlParserFactory()));
new XmlMapsGDataParserFactory(new AndroidXmlParserFactory()));
docListWrapper.setClient(docsGdataClient);
// First try to find the spreadsheet:
@@ -51,7 +51,6 @@ import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Vector;
/**
@@ -73,7 +72,7 @@ public class SendToFusionTables implements Runnable {
public static final String SERVICE_ID = "fusiontables";
/** The path for viewing a map visualization of a table. */
private static final String FUSIONTABLES_MAP =
private static final String FUSIONTABLES_MAP =
"http://www.google.com/fusiontables/embedviz?" +
"viz=MAP&q=select+col0,+col1,+col2,+col3+from+%s+&h=false&" +
"lat=%f&lng=%f&z=%d&t=1&l=col2";
@@ -85,10 +84,10 @@ public class SendToFusionTables implements Runnable {
private static final int MAX_POINTS_PER_UPLOAD = 2048;
private static final String GDATA_VERSION = "2";
// This class reports upload status to the user as a completion percentage
// using a progress bar. Progress is defined as follows:
//
//
// 0% Getting track metadata
// 5% Creating Fusion Table (GData to FT server)
// 10%-90% Uploading the track data to Fusion Tables
@@ -161,18 +160,13 @@ public class SendToFusionTables implements Runnable {
double latE6 = stats.getBottom() + (stats.getTop() - stats.getBottom()) / 2;
double lonE6 = stats.getLeft() + (stats.getRight() - stats.getLeft()) / 2;
int z = 15;
// We explicitly format with Locale.US because we need the latitude and
// longitude to be formatted in a locale-independent manner. Specifically,
// we need the decimal separator to be a period rather than a comma.
return String.format(Locale.US, FUSIONTABLES_MAP, track.getTableId(),
latE6 / 1.E6, lonE6 / 1.E6, z);
return String.format(FUSIONTABLES_MAP, track.getTableId(), latE6 / 1.E6, lonE6 / 1.E6, z);
}
private void doUpload() {
((GoogleHeaders) transport.defaultHeaders).setGoogleLogin(auth.getAuthToken());
int statusMessageId = R.string.error_sending_to_fusiontables;
boolean success = false;
boolean success = true;
try {
progressIndicator.setProgressValue(PROGRESS_INITIALIZATION);
progressIndicator.setProgressMessage(R.string.progress_message_reading_track);
@@ -195,20 +189,19 @@ public class SendToFusionTables implements Runnable {
if (!uploadAllTrackPoints(track, originalDescription)) {
return;
}
progressIndicator.setProgressValue(PROGRESS_UPLOAD_WAYPOINTS);
// Upload all the waypoints.
if (!uploadWaypoints(track)) {
return;
}
statusMessageId = R.string.status_new_fusiontable_has_been_created;
success = true;
Log.d(MyTracksConstants.TAG, "SendToFusionTables: Done: " + success);
progressIndicator.setProgressValue(PROGRESS_COMPLETE);
} finally {
final boolean finalSuccess = success;
final int finalStatusMessageId = statusMessageId;
context.runOnUiThread(new Runnable() {
@@ -260,7 +253,7 @@ public class SendToFusionTables implements Runnable {
builder.append(')');
return builder.toString();
}
private static String sqlEscape(String value) {
return value.replaceAll("'", "''");
}
@@ -639,8 +632,8 @@ public class SendToFusionTables implements Runnable {
double totalPercentage =
(totalLocationsRead + totalLocationsPrepared + totalLocationsUploaded)
/ (totalLocations * 3);
double scaledPercentage = totalPercentage
double scaledPercentage = totalPercentage
* (PROGRESS_UPLOAD_DATA_MAX - PROGRESS_UPLOAD_DATA_MIN) + PROGRESS_UPLOAD_DATA_MIN;
progressIndicator.setProgressValue((int) scaledPercentage);
@@ -677,7 +670,7 @@ public class SendToFusionTables implements Runnable {
try {
response = request.execute();
} catch (HttpResponseException e) {
throw new GDataWrapper.HttpException(e.response.statusCode, e.response.statusMessage);
throw new GDataWrapper.HttpException(e.response.statusCode, e.getMessage());
}
boolean success = response.isSuccessStatusCode;
if (success) {
@@ -1,458 +0,0 @@
/*
* 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
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.MyTracksSettings;
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.Waypoint;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade.WaypointData;
import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.MyTracksUtils;
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.Activity;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.location.Location;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
/**
* A helper class used to transmit tracks to Google MyMaps.
* A new instance should be used for each upload.
*
* IMPORTANT: while this code is Apache-licensed, please notice that usage of
* the Google Maps servers through this API is only allowed for the My Tracks
* application. Other applications looking to upload maps data should look
* into using the Fusion Tables API.
*
* @author Leif Hendrik Wilden
*/
public class SendToMyMaps implements Runnable {
public static final String NEW_MAP_ID = "new";
private static final int MAX_POINTS_PER_UPLOAD = 2048;
private final Activity context;
private final AuthManager auth;
private final long trackId;
private final ProgressIndicator progressIndicator;
private final OnSendCompletedListener onCompletion;
private final StringUtils stringUtils;
private final MyTracksProviderUtils providerUtils;
private String mapId;
private MapsFacade mapsClient;
// Progress status
private int totalLocationsRead;
private int totalLocationsPrepared;
private int totalLocationsUploaded;
private int totalLocations;
private int totalSegmentsUploaded;
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) {
this.context = context;
this.mapId = mapId;
this.auth = auth;
this.trackId = trackId;
this.progressIndicator = progressIndicator;
this.onCompletion = onCompletion;
this.stringUtils = new StringUtils(context);
this.providerUtils = MyTracksProviderUtils.Factory.get(context);
}
@Override
public void run() {
Log.d(MyTracksConstants.TAG, "Sending to MyMaps: trackId = " + trackId);
doUpload();
}
private void doUpload() {
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);
String originalDescription = track.getDescription();
track.setDescription("<p>" + track.getDescription() + "</p><p>"
+ stringUtils.generateTrackDescription(track, null, null) + "</p>");
mapsClient = MyMapsFactory.newMapsClient(context, auth);
// Create a new map if necessary:
boolean isNewMap = mapId.equals(NEW_MAP_ID);
if (isNewMap) {
SharedPreferences preferences = context.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
boolean mapPublic = true;
if (preferences != null) {
mapPublic = preferences.getBoolean(
context.getString(R.string.default_map_public_key), true);
}
progressIndicator.setProgressMessage(
R.string.progress_message_creating_map);
StringBuilder mapIdBuilder = new StringBuilder();
success = mapsClient.createNewMap(
track.getName(), track.getCategory(), originalDescription, mapPublic, mapIdBuilder);
mapId = mapIdBuilder.toString();
}
// Upload all of the segments of the track plus start/end markers
if (success) {
success = uploadAllTrackPoints(track, originalDescription);
}
// Put waypoints.
if (success) {
Cursor c = providerUtils.getWaypointsCursor(
track.getId(), 0,
MyTracksConstants.MAX_LOADED_WAYPOINTS_POINTS);
if (c != null) {
try {
if (c.getCount() > 1 && c.moveToFirst()) {
// This will skip the 1st waypoint (it carries the stats for the
// last segment).
ArrayList<WaypointData> waypoints = new ArrayList<WaypointData>(c.getCount() - 1);
while (c.moveToNext()) {
Waypoint wpt = providerUtils.createWaypoint(c);
waypoints.add(new WaypointData(
wpt.getName(), wpt.getDescription(), wpt.getIcon(), wpt.getLocation()));
}
success = mapsClient.uploadWaypoints(mapId, waypoints);
}
} finally {
c.close();
}
} else {
success = false;
}
if (!success) {
Log.w(MyTracksConstants.TAG,
"SendToMyMaps: upload waypoints failed.");
}
}
if (success) {
statusMessageId = isNewMap
? R.string.status_new_mymap_has_been_created
: R.string.status_tracks_have_been_uploaded;
}
Log.d(MyTracksConstants.TAG, "SendToMyMaps: Done: " + success);
progressIndicator.setProgressValue(100);
} finally {
if (mapsClient != null) {
mapsClient.cleanUp();
}
final boolean finalSuccess = success;
final int finalStatusMessageId = statusMessageId;
context.runOnUiThread(new Runnable() {
public void run() {
if (onCompletion != null) {
onCompletion.onSendCompleted(
mapId, finalSuccess, finalStatusMessageId);
}
}
});
}
}
private boolean uploadAllTrackPoints(
final Track track, String originalDescription) {
SharedPreferences preferences = context.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
boolean metricUnits = true;
if (preferences != null) {
metricUnits =
preferences.getBoolean(context.getString(R.string.metric_units_key),
true);
}
Cursor locationsCursor =
providerUtils.getLocationsCursor(track.getId(), 0, -1, false);
try {
if (!locationsCursor.moveToFirst()) {
Log.w(MyTracksConstants.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));
Log.d(MyTracksConstants.TAG,
"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(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
progressIndicator.setProgressMessage(
R.string.progress_message_reading_track);
Location lastLocation = null;
do {
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 && MyTracksUtils.isValidLocation(loc)) {
// All points go into the smoothing buffer...
elevationBuffer.setNext(metricUnits ? loc.getAltitude()
: loc.getAltitude() * UnitConversions.M_TO_FT);
if (lastLocation != null) {
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) {
if (!prepareAndUploadPoints(track, locations)) {
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(),
lastLocation, false);
}
return true;
} finally {
locationsCursor.close();
}
}
private boolean prepareAndUploadPoints(Track track, List<Location> locations) {
progressIndicator.setProgressMessage(
R.string.progress_message_preparing_track);
updateProgress();
int numLocations = locations.size();
if (numLocations < 2) {
Log.d(MyTracksConstants.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);
for (Track splitTrack : splitTracks) {
if (totalSegmentsUploaded > 1) {
splitTrack.setName(splitTrack.getName() + " "
+ String.format(
context.getString(R.string.part), totalSegmentsUploaded));
}
totalSegmentsUploaded++;
Log.d(MyTracksConstants.TAG,
"SendToMyMaps: Prepared feature for upload w/ "
+ splitTrack.getLocations().size() + " points.");
// Transmit tracks via GData feed:
// -------------------------------
Log.d(MyTracksConstants.TAG,
"SendToMyMaps: Uploading to map " + mapId + " w/ auth " + auth);
if (!mapsClient.uploadTrackPoints(mapId, splitTrack.getName(), splitTrack.getLocations())) {
Log.e(MyTracksConstants.TAG, "Uploading failed");
return false;
}
}
locations.clear();
totalLocationsUploaded += numLocations;
updateProgress();
return true;
}
/**
* Prepares a buffer of locations for transmission to google maps.
*
* @param track the original track with meta data
* @param buffer a buffer of locations on the track
* @return an array of tracks each with a sub section of the points in the
* original buffer
*/
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();
TripStatistics trackStats = track.getStatistics();
segment.setId(track.getId());
segment.setName(track.getName());
segment.setDescription(/* track.getDescription() */ "");
segment.setCategory(track.getCategory());
segmentStats.setStartTime(trackStats.getStartTime());
segmentStats.setStopTime(trackStats.getStopTime());
boolean startNewTrackSegment = false;
for (Location loc : locations) {
if (totalLocationsPrepared % 100 == 0) {
updateProgress();
}
if (loc.getLatitude() > 90) {
startNewTrackSegment = true;
}
if (startNewTrackSegment) {
// Close up the last segment.
prepareTrackSegment(segment, splitTracks);
Log.d(MyTracksConstants.TAG,
"MyTracksSendToMyMaps: Starting new track segment...");
startNewTrackSegment = false;
segment = new Track();
segment.setId(track.getId());
segment.setName(track.getName());
segment.setDescription(/* track.getDescription() */ "");
segment.setCategory(track.getCategory());
}
if (loc.getLatitude() <= 90) {
segment.addLocation(loc);
if (segmentStats.getStartTime() < 0) {
segmentStats.setStartTime(loc.getTime());
}
}
totalLocationsPrepared++;
}
prepareTrackSegment(segment, splitTracks);
return splitTracks;
}
/**
* Prepares a track segment for sending to google maps.
* The main steps are:
* - correcting end time
* - decimating locations
* - splitting into smaller tracks.
*
* The final track pieces will be put in the array list splitTracks.
*
* @param segment the original segment of the track
* @param splitTracks an array of smaller track segments
*/
private void prepareTrackSegment(
Track segment, ArrayList<Track> splitTracks) {
TripStatistics segmentStats = segment.getStatistics();
if (segmentStats.getStopTime() < 0
&& segment.getLocations().size() > 0) {
segmentStats.setStopTime(segment.getLocations().size() - 1);
}
/*
* Decimate to 2 meter precision. Mapshop doesn't like too many
* points:
*/
MyTracksUtils.decimate(segment, 2.0);
/* It the track still has > 500 points, split it in pieces: */
if (segment.getLocations().size() > 500) {
splitTracks.addAll(MyTracksUtils.split(segment, 500));
} else if (segment.getLocations().size() >= 2) {
splitTracks.add(segment);
}
}
/**
* Sets the current upload progress.
*/
private void updateProgress() {
// The percent of the total that represents the completed part of this
// segment.
int totalPercentage =
(totalLocationsRead + totalLocationsPrepared + totalLocationsUploaded)
/ (totalLocations * 3);
totalPercentage = Math.min(99, totalPercentage);
progressIndicator.setProgressValue(totalPercentage);
}
}
@@ -255,8 +255,9 @@ public class TrackWriter {
void writeDocument() {
Log.d(MyTracksConstants.TAG, "Started writing track.");
writer.writeHeader();
writeWaypoints(track.getId());
// TODO: Fix ordering (in GPX waypoints should come first)
writeLocations();
writeWaypoints(track.getId());
writer.writeFooter();
writer.close();
success = true;
@@ -187,7 +187,6 @@ public class AndroidGDataClient implements GDataClient {
while (redirectsLeft > 0) {
HttpUriRequest request = creator.createRequest(uri);
request.addHeader("User-Agent", "Android-GData");
request.addHeader("Accept-Encoding", "gzip");
// only add the auth token if not null (to allow for GData feeds that do
@@ -210,10 +210,9 @@ public class GDataWrapper<C> {
errorType = ERROR_AUTH;
errorMessage = e.getMessage();
} catch (HttpException e) {
Log.e(MyTracksConstants.TAG,
"HttpException, code " + e.getStatusCode() + " message " + e.getMessage(), e);
Log.e(MyTracksConstants.TAG, "HttpException", e);
errorMessage = e.getMessage();
if (e.getStatusCode() == 401) {
if (errorMessage.contains("401")) {
errorType = ERROR_AUTH;
} else {
errorType = ERROR_CONNECTION;
@@ -225,7 +224,7 @@ public class GDataWrapper<C> {
} catch (IOException e) {
Log.e(MyTracksConstants.TAG, "Exception", e);
errorMessage = e.getMessage();
if (errorMessage != null && errorMessage.contains("503")) {
if (errorMessage.contains("503")) {
errorType = ERROR_INTERNAL;
} else {
errorType = ERROR_CONNECTION;
@@ -1,106 +0,0 @@
/*
* 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 com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.view.View;
import android.widget.ListView;
import java.util.List;
/**
* Creates the dialog used to display the results of sending track data to
* Google. The dialog lists the services to which data was uploaded, along
* with an indicator of success/failure. If possible, a button is displayed
* offering to share the uploaded track.
*
* Implementation note: This class is a factory, rather than a {@link Dialog}
* subclass, because alert dialogs have to be created with
* {@link AlertDialog.Builder}. Attempts to subclass {@link AlertDialog}
* directly have been unsuccessful, as {@link AlertDialog.Builder} uses a
* private subclass to implement most of the interesting behavior.
*
* @author Matthew Simmons
*/
public class ResultDialogFactory {
private ResultDialogFactory() {}
/**
* Create a send-to-Google result dialog. The caller is responsible for
* showing it.
*
* @param activity the activity associated with the dialog
* @param results the results to be displayed in the dialog
* @param onOkClickListener the listener to invoke if the OK button is
* clicked
* @param onShareClickListener the listener to invoke if the Share button is
* clicked. If no share listener is provided, the Share button will not
* be displayed.
* @return the created dialog
*/
public static AlertDialog makeDialog(Activity activity, List<SendResult> results,
DialogInterface.OnClickListener onOkClickListener,
DialogInterface.OnClickListener onShareClickListener) {
boolean success = true;
for (SendResult result : results) {
if (!result.isSuccess()) {
success = false;
break;
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(activity)
.setView(makeDialogContent(activity, results, success));
if (success) {
builder.setTitle(R.string.success);
builder.setIcon(android.R.drawable.ic_dialog_info);
} else {
builder.setTitle(R.string.error);
builder.setIcon(android.R.drawable.ic_dialog_alert);
}
builder.setPositiveButton(activity.getString(R.string.ok), onOkClickListener);
if (onShareClickListener != null) {
builder.setNeutralButton(activity.getString(R.string.share_track),
onShareClickListener);
}
return builder.create();
}
private static View makeDialogContent(Activity activity, List<SendResult> results,
boolean success) {
ResultListAdapter resultListAdapter = new ResultListAdapter(activity,
R.layout.send_to_google_result_list_item, results);
View content = activity.getLayoutInflater().inflate(R.layout.send_to_google_result, null);
ListView resultList = (ListView) content.findViewById(R.id.send_to_google_result_list);
resultList.setAdapter(resultListAdapter);
content.findViewById(R.id.send_to_google_result_comment)
.setVisibility(success ? View.VISIBLE : View.GONE);
content.findViewById(R.id.send_to_google_result_error)
.setVisibility(success ? View.GONE : View.VISIBLE);
return content;
}
}
@@ -1,85 +0,0 @@
/*
* 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 com.google.android.maps.mytracks.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;
import java.util.List;
/**
* This class implements the {@link ListAdapter} used by the send-to-Google
* result dialog created by {@link ResultDialogFactory}. It generates views
* for each entry in an array of {@link SendResult} instances.
* @author Matthew Simmons
*/
class ResultListAdapter extends ArrayAdapter<SendResult> {
public ResultListAdapter(Context context, int textViewResourceId, List<SendResult> results) {
super(context, textViewResourceId, results);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
LayoutInflater inflater
= (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.send_to_google_result_list_item, null);
}
SendResult result = getItem(position);
setImage(view, result.isSuccess() ? R.drawable.success : R.drawable.failure);
setName(view, result.getType().getServiceName());
setUrl(view, result.getType().getServiceUrl());
return view;
}
@Override
public boolean areAllItemsEnabled() {
// We don't want the displayed items to be clickable
return false;
}
// The following protected methods exist to be overridden for testing
// purposes. Doing so insulates the test class from the details of the
// layout.
protected void setImage(View content, int drawableId) {
ImageView imageView = (ImageView) content.findViewById(R.id.send_to_google_result_icon);
imageView.setImageDrawable(getContext().getResources().getDrawable(drawableId));
}
protected void setName(View content, int nameId) {
setTextViewText(content, R.id.send_to_google_result_name, nameId);
}
protected void setUrl(View content, int urlId) {
setTextViewText(content, R.id.send_to_google_result_url, urlId);
}
private void setTextViewText(View content, int viewId, int textId) {
TextView textView = (TextView) content.findViewById(viewId);
textView.setText(getContext().getString(textId));
}
};
@@ -1,46 +0,0 @@
/*
* 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;
/**
* This class represents the the result of the uploading of track data to a
* single service.
*
* @author Matthew Simmons
*/
public class SendResult {
private final SendType type;
private final boolean success;
/**
* @param type the service to which track data was uploaded
* @param success true if the uploading succeeded
*/
public SendResult(SendType type, boolean success) {
this.type = type;
this.success = success;
}
/** Returns the service to which the track data was uploaded */
public SendType getType() {
return type;
}
/** Returns true if the uploading succeeded */
public boolean isSuccess() {
return success;
}
}
@@ -1,50 +0,0 @@
/*
* 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 com.google.android.maps.mytracks.R;
/**
* Enumerates the services to which we can upload track data.
*
* @author Matthew Simmons
*/
public enum SendType {
MYMAPS(R.string.sendtogoogle_google_mymaps,
R.string.sendtogoogle_google_mymaps_url),
FUSION_TABLES(R.string.sendtogoogle_google_fusiontables,
R.string.sendtogoogle_google_fusiontables_url),
DOCS(R.string.sendtogoogle_google_docs,
R.string.sendtogoogle_google_docs_url);
private int serviceName;
private int serviceUrl;
private SendType(int serviceName, int serviceUrl) {
this.serviceName = serviceName;
this.serviceUrl = serviceUrl;
}
/** Returns the resource ID for the printable (short) name of the service */
public int getServiceName() {
return serviceName;
}
/** Returns the resource ID for the service's URL */
public int getServiceUrl() {
return serviceUrl;
}
}
@@ -1,78 +0,0 @@
/*
* 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.MyTracksConstants.TAG;
import android.content.Context;
import android.media.AudioManager;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
import android.util.Log;
import java.util.HashMap;
/**
* This class will periodically announce the user's trip statistics for Froyo and future handsets.
* This class will request and release audio focus.
*
* @author Sandor Dornbush
*/
public class FroyoStatusAnnouncerTask extends StatusAnnouncerTask {
private final static HashMap<String, String> SPEECH_PARAMS = new HashMap<String, String>();
static {
SPEECH_PARAMS.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "not_used");
}
private final AudioManager audioManager;
private final OnUtteranceCompletedListener utteranceListener =
new OnUtteranceCompletedListener() {
@Override
public void onUtteranceCompleted(String utteranceId) {
if (audioManager != null) {
Log.d(TAG, "FroyoStatusAnnouncerTask: Abandoning audio focus.");
audioManager.abandonAudioFocus(null);
}
}
};
public FroyoStatusAnnouncerTask(Context context) {
super(context);
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
@Override
protected void onTtsInit(int status) {
super.onTtsInit(status);
if (status == TextToSpeech.SUCCESS) {
tts.setOnUtteranceCompletedListener(utteranceListener);
}
}
@Override
protected void speakAnnouncment(String announcement) {
int result = audioManager.requestAudioFocus(null,
TextToSpeech.Engine.DEFAULT_STREAM,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
if (result == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
Log.w(TAG, "FroyoStatusAnnouncerTask: Request audio focus failed.");
}
// We don't care about the utterance id.
// It is supplied here to force onUtteranceCompleted to be called.
tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, SPEECH_PARAMS);
}
}
@@ -41,11 +41,7 @@ public class StatusAnnouncerFactory {
*/
public PeriodicTask create(Context context) {
if (hasTts) {
if (ApiFeatures.getInstance().isAudioFocusSupported()) {
return new FroyoStatusAnnouncerTask(context);
} else {
return new StatusAnnouncerTask(context);
}
return new StatusAnnouncerTask(context);
} else {
return null;
}
@@ -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
@@ -59,7 +59,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
/**
* The interface to the text to speech engine.
*/
protected TextToSpeech tts;
private TextToSpeech tts;
/**
* The response received from the TTS engine after initialization.
@@ -98,7 +98,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
/**
* Called when the TTS engine is initialized.
*/
protected void onTtsInit(int status) {
private void onTtsInit(int status) {
Log.i(MyTracksConstants.TAG, "TrackRecordingService.TTS init: " + status);
this.ready = status == TextToSpeech.SUCCESS;
@@ -128,25 +128,6 @@ public class StatusAnnouncerTask implements PeriodicTask {
*/
@Override
public void run(TrackRecordingService service) {
if (service == null) {
Log.e(MyTracksConstants.TAG, "StatusAnnouncer TrackRecordingService not initialized");
return;
}
runWithStatistics(service.getTripStatistics());
}
/**
* This method exists as a convenience for testing code, allowing said code
* to avoid needing to instantiate an entire {@link TrackRecordingService}
* just to test the announcer.
*/
protected void runWithStatistics(TripStatistics statistics) {
if (statistics == null) {
Log.e(MyTracksConstants.TAG, "StatusAnnouncer stats not initialized.");
return;
}
if (!ready || tts == null) {
Log.e(MyTracksConstants.TAG, "StatusAnnouncer Tts not ready.");
return;
@@ -158,12 +139,13 @@ public class StatusAnnouncerTask implements PeriodicTask {
return;
}
String announcement = getAnnouncement(statistics);
Log.d(MyTracksConstants.TAG, "Announcement: " + announcement);
speakAnnouncment(announcement);
}
if (service == null || service.getTripStatistics() == null) {
Log.e(MyTracksConstants.TAG, "StatusAnnouncer stats not initialized.");
return;
}
protected void speakAnnouncment(String announcement) {
String announcement = getAnnouncement(service.getTripStatistics());
Log.d(MyTracksConstants.TAG, "Announcement: " + announcement);
tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, null);
}
@@ -179,7 +161,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
boolean metricUnits = true;
boolean reportSpeed = true;
if (preferences != null) {
metricUnits =
metricUnits =
preferences.getBoolean(context.getString(R.string.metric_units_key),
true);
reportSpeed =
@@ -23,12 +23,12 @@ import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TracksColumns;
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.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.services.sensors.SensorManager;
import com.google.android.apps.mytracks.services.sensors.SensorManagerFactory;
import com.google.android.apps.mytracks.stats.TripStatistics;
@@ -62,8 +62,6 @@ import android.util.Log;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* A background service that registers a location listener and records track
@@ -86,8 +84,8 @@ public class TrackRecordingService extends Service implements LocationListener {
private int minRequiredAccuracy =
MyTracksSettings.DEFAULT_MIN_REQUIRED_ACCURACY;
private int autoResumeTrackTimeout =
MyTracksSettings.DEFAULT_AUTO_RESUME_TRACK_TIMEOUT;
MyTracksSettings.DEFAULT_AUTO_RESUME_TRACK_TIMEOUT;
private long recordingTrackId = -1;
private long currentWaypointId = -1;
@@ -117,9 +115,9 @@ public class TrackRecordingService extends Service implements LocationListener {
private SplitManager splitManager;
private SensorManager sensorManager;
private PreferenceManager prefManager;
/**
* The interval in milliseconds that we have requested to be notified of gps
* readings.
@@ -168,7 +166,7 @@ public class TrackRecordingService extends Service implements LocationListener {
* The most recent recording track.
*/
private Track recordingTrack;
/**
* Is the service currently recording a track?
*/
@@ -189,8 +187,6 @@ public class TrackRecordingService extends Service implements LocationListener {
*/
private int announcementFrequency = -1;
private ExecutorService executerServce;
/*
* Utility functions
*/
@@ -409,7 +405,7 @@ public class TrackRecordingService extends Service implements LocationListener {
Log.d(MyTracksConstants.TAG,
"Location listener now unregistered w/ TrackRecordingService.");
}
private Track getRecordingTrack() {
if (recordingTrackId < 0) {
return null;
@@ -421,10 +417,9 @@ public class TrackRecordingService extends Service implements LocationListener {
private void restoreStats(Track track) {
Log.d(MyTracksConstants.TAG,
"Restoring stats of track with ID: " + track.getId());
TripStatistics stats = track.getStatistics();
statsBuilder = new TripStatisticsBuilder(stats.getStartTime());
statsBuilder.setMinRecordingDistance(minRecordingDistance);
setUpAnnouncer();
splitManager.restore();
@@ -441,7 +436,6 @@ public class TrackRecordingService extends Service implements LocationListener {
waypointStatsBuilder = new TripStatisticsBuilder(stats.getStartTime());
currentWaypointId = -1;
}
waypointStatsBuilder.setMinRecordingDistance(minRecordingDistance);
Cursor cursor = null;
try {
@@ -481,18 +475,9 @@ public class TrackRecordingService extends Service implements LocationListener {
/*
* Location listener implementation: =================================
*/
@Override
public void onLocationChanged(final Location location) {
this.executerServce.submit(
new Runnable() {
@Override
public void run() {
onLocationChangedAsync(location);
}
});
}
private void onLocationChangedAsync(Location location) {
@Override
public void onLocationChanged(Location location) {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.onLocationChanged");
try {
@@ -528,7 +513,6 @@ public class TrackRecordingService extends Service implements LocationListener {
// Update the idle time if needed.
locationListenerPolicy.updateIdleTime(statsBuilder.getIdleTime());
addLocationToStats(location);
if (currentRecordingInterval !=
locationListenerPolicy.getDesiredPollingInterval()) {
registerLocationListener();
@@ -554,6 +538,8 @@ public class TrackRecordingService extends Service implements LocationListener {
// two and ignore the rest. This code will only have an effect if the
// maxRecordingDistance = 0
if (distanceToLast == 0 && !hasSensorData) {
addLocationToStats(location);
if (isMoving) {
Log.d(MyTracksConstants.TAG, "Found two identical locations.");
isMoving = false;
@@ -575,6 +561,7 @@ public class TrackRecordingService extends Service implements LocationListener {
}
} else if (distanceToLastRecorded > minRecordingDistance
|| hasSensorData) {
addLocationToStats(location);
if (lastLocation != null && !isMoving) {
// Last location was the last stationary location. Need to go back and
// add it.
@@ -688,7 +675,6 @@ public class TrackRecordingService extends Service implements LocationListener {
prefManager.setRecordingTrack(recordingTrackId = -1);
}
showNotification();
executerServce = Executors.newSingleThreadExecutor();
}
/**
@@ -721,7 +707,7 @@ public class TrackRecordingService extends Service implements LocationListener {
});
}
}
private void shutdownAnnouncer() {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.shutdownAnnouncer: "
+ announcementExecuter);
@@ -764,7 +750,7 @@ public class TrackRecordingService extends Service implements LocationListener {
// This should be the last operation.
releaseWakeLock();
super.onDestroy();
}
@@ -786,7 +772,7 @@ public class TrackRecordingService extends Service implements LocationListener {
unregisterLocationListener();
return super.stopService(name);
}
@Override
public void onStart(Intent intent, int startId) {
handleStartCommand(intent, startId);
@@ -806,36 +792,36 @@ public class TrackRecordingService extends Service implements LocationListener {
if (intent != null &&
intent.getBooleanExtra(RESUME_TRACK_EXTRA_NAME, false)) {
Log.d(MyTracksConstants.TAG, "TrackRecordingService: requested resume");
// Make sure that the current track exists and is fresh enough.
if (recordingTrack == null || !shouldResumeTrack(recordingTrack)) {
Log.i(MyTracksConstants.TAG,
"TrackRecordingService: Not resuming, because the previous track ("
+ recordingTrack + ") doesn't exist or is too old");
isRecording = false;
prefManager.setRecordingTrack(recordingTrackId = -1);
prefManager.setRecordingTrack(recordingTrackId = -1);
stopSelfResult(startId);
return;
}
Log.i(MyTracksConstants.TAG, "TrackRecordingService: resuming");
}
}
private void setAutoResumeTrackRetries(
SharedPreferences sharedPreferences, int retryAttempts) {
Log.d(MyTracksConstants.TAG,
"Updating auto-resume retry attempts to: " + retryAttempts);
prefManager.setAutoResumeTrackCurrentRetry(retryAttempts);
}
private boolean shouldResumeTrack(Track track) {
Log.d(MyTracksConstants.TAG, "shouldResumeTrack: autoResumeTrackTimeout = "
+ autoResumeTrackTimeout);
// Check if we haven't exceeded the maximum number of retry attempts.
SharedPreferences sharedPreferences =
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
int retries = sharedPreferences.getInt(
getString(R.string.auto_resume_track_current_retry_key), 0);
Log.d(MyTracksConstants.TAG,
@@ -853,7 +839,7 @@ public class TrackRecordingService extends Service implements LocationListener {
// Check for special cases.
if (autoResumeTrackTimeout == 0) {
// Never resume.
// Never resume.
Log.d(MyTracksConstants.TAG,
"shouldResumeTrack: Auto-resume disabled (never resume)");
return false;
@@ -871,7 +857,7 @@ public class TrackRecordingService extends Service implements LocationListener {
"shouldResumeTrack: lastModified = " + lastModified
+ ", autoResumeTrackTimeout: " + autoResumeTrackTimeout);
return lastModified > 0 && System.currentTimeMillis() - lastModified <=
autoResumeTrackTimeout * 60 * 1000;
autoResumeTrackTimeout * 60 * 1000;
}
public boolean isRecording() {
@@ -897,19 +883,11 @@ public class TrackRecordingService extends Service implements LocationListener {
}
wpt.setTrackId(recordingTrackId);
wpt.setLength(length);
if (lastValidLocation == null) {
// A null location is ok, and expected on track start.
// Make it an impossible location.
Location l = new Location("");
l.setLatitude(100);
l.setLongitude(180);
wpt.setLocation(l);
} else {
if (lastValidLocation != null) {
// A null location is ok, and expected on track start.
wpt.setLocation(lastLocation);
if (lastLocation != null) {
wpt.setDuration(lastLocation.getTime() - statsBuilder.getStatistics().getStartTime());
}
wpt.setDuration(lastLocation.getTime()
- statsBuilder.getStatistics().getStartTime());
}
Uri uri = providerUtils.insertWaypoint(wpt);
return Long.parseLong(uri.getLastPathSegment());
@@ -962,27 +940,27 @@ public class TrackRecordingService extends Service implements LocationListener {
// Create a new stats keeper for the next marker.
waypointStatsBuilder = new TripStatisticsBuilder(time);
}
private ServiceBinder binder = new ServiceBinder(this);
/**
* TODO: There is a bug in Android that leaks Binder instances. This bug is
* especially visible if we have a non-static class, as there is no way to
* nullify reference to the outer class (the service).
* A workaround is to use a static class and explicitly clear service
* and detach it from the underlying Binder. With this approach, we minimize
* the leak to 24 bytes per each service instance.
* the leak to 24 bytes per each service instance.
*
* For more details, see the following bug:
* http://code.google.com/p/android/issues/detail?id=6426.
*/
private static class ServiceBinder extends ITrackRecordingService.Stub {
private TrackRecordingService service;
public ServiceBinder(TrackRecordingService service) {
this.service = service;
}
/**
* Clears the reference to the outer class to minimize the leak.
*/
@@ -990,7 +968,7 @@ public class TrackRecordingService extends Service implements LocationListener {
this.service = null;
attachInterface(null, null);
}
@Override
public boolean isRecording() {
checkService();
@@ -1005,13 +983,13 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override
public long getRecordingTrackId() {
checkService();
checkService();
return service.recordingTrackId;
}
@Override
public boolean hasRecorded() {
checkService();
checkService();
return service.providerUtils.getLastTrackId() >= 0;
}
@@ -1049,13 +1027,13 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override
public void recordLocation(Location loc) {
checkService();
checkService();
service.onLocationChanged(loc);
}
@Override
public byte[] getSensorData() {
checkService();
checkService();
if (service.sensorManager == null) {
Log.d(MyTracksConstants.TAG, "No sensor manager for data.");
return null;
@@ -1069,7 +1047,7 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override
public int getSensorState() {
checkService();
checkService();
if (service.sensorManager == null) {
Log.d(MyTracksConstants.TAG, "No sensor manager for data.");
return Sensor.SensorState.NONE.getNumber();
@@ -1098,12 +1076,10 @@ public class TrackRecordingService extends Service implements LocationListener {
recordingTrackId, startTime));
isRecording = true;
isMoving = true;
providerUtils.updateTrack(track);
statsBuilder = new TripStatisticsBuilder(startTime);
statsBuilder.setMinRecordingDistance(minRecordingDistance);
waypointStatsBuilder = new TripStatisticsBuilder(startTime);
waypointStatsBuilder.setMinRecordingDistance(minRecordingDistance);
currentWaypointId = insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
setUpAnnouncer();
length = 0;
@@ -1156,12 +1132,12 @@ public class TrackRecordingService extends Service implements LocationListener {
showNotification();
long recordedTrackId = recordingTrackId;
prefManager.setRecordingTrack(recordingTrackId = -1);
if (sensorManager != null) {
sensorManager.shutdown();
sensorManager = null;
}
releaseWakeLock();
// Notify the world that we're no longer recording.
@@ -1221,10 +1197,6 @@ public class TrackRecordingService extends Service implements LocationListener {
public void setMinRecordingDistance(int minRecordingDistance) {
this.minRecordingDistance = minRecordingDistance;
if (statsBuilder != null && waypointStatsBuilder != null) {
statsBuilder.setMinRecordingDistance(minRecordingDistance);
waypointStatsBuilder.setMinRecordingDistance(minRecordingDistance);
}
}
public int getMinRequiredAccuracy() {
@@ -1243,11 +1215,11 @@ public class TrackRecordingService extends Service implements LocationListener {
LocationListenerPolicy locationListenerPolicy) {
this.locationListenerPolicy = locationListenerPolicy;
}
public int getAutoResumeTrackTimeout() {
return autoResumeTrackTimeout;
}
public void setAutoResumeTrackTimeout(int autoResumeTrackTimeout) {
this.autoResumeTrackTimeout = autoResumeTrackTimeout;
}
@@ -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
@@ -16,16 +16,12 @@
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.maps.mytracks.R;
import com.dsi.ant.AntDefine;
import com.dsi.ant.AntMesg;
import com.dsi.ant.exception.AntInterfaceException;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.services.sensors.ant.AntChannelIdMessage;
import com.google.android.apps.mytracks.services.sensors.ant.AntChannelResponseMessage;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
@@ -53,70 +49,62 @@ public class AntDirectSensorManager extends AntSensorManager {
public AntDirectSensorManager(Context context) {
super(context);
deviceNumberHRM = WILDCARD;
// First read the the device id that we will be pairing with.
SharedPreferences prefs = context.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
if (prefs != null) {
deviceNumberHRM =
deviceNumberHRM =
(short) prefs.getInt(context.getString(R.string.ant_heart_rate_sensor_id_key), 0);
}
Log.i(TAG, "Will pair with heart rate monitor: " + deviceNumberHRM);
Log.i(TAG, "Pairing with heart rate monitor: " + deviceNumberHRM);
}
@Override
protected boolean handleMessage(byte messageId, byte[] messageData) {
if (super.handleMessage(messageId, messageData)) {
return true;
}
int channel = messageData[0] & AntDefine.CHANNEL_NUMBER_MASK;
public void handleMessage(byte[] antMessage) {
int channel =
antMessage[AntMesg.MESG_DATA_OFFSET] & AntDefine.CHANNEL_NUMBER_MASK;
switch (channel) {
case HRM_CHANNEL:
antDecodeHRM(messageId, messageData);
antDecodeHRM(antMessage);
break;
default:
Log.d(TAG, "Unhandled message: " + channel);
}
return true;
}
/**
* Decode an ant heart rate monitor message.
* @param messageData The byte array received from the heart rate monitor.
* @param antMessage The byte array received from the heart rate monitor.
*/
private void antDecodeHRM(int messageId, byte[] messageData) {
switch (messageId) {
private void antDecodeHRM(byte[] antMessage) {
// message ID == broadcast
switch (antMessage[AntMesg.MESG_ID_OFFSET]) {
case AntMesg.MESG_BROADCAST_DATA_ID:
handleBroadcastData(messageData);
handleBroadcastData(antMessage);
break;
case AntMesg.MESG_RESPONSE_EVENT_ID:
handleMessageResponse(messageData);
handleMessageResponse(antMessage);
break;
case AntMesg.MESG_CHANNEL_ID_ID:
handleChannelId(messageData);
handleChannelId(antMessage);
break;
default:
Log.e(TAG, "Unexpected message id: " + messageId);
Log.e(TAG, "Unexpected message id: " + antMessage[3]);
}
}
private void handleBroadcastData(byte[] antMessage) {
if (deviceNumberHRM == WILDCARD) {
try {
getAntReceiver().ANTRequestMessage(HRM_CHANNEL,
AntMesg.MESG_CHANNEL_ID_ID);
} catch (AntInterfaceException e) {
Log.e(TAG, "ANT error handling broadcast data", e);
}
getAntReceiver().ANTRequestMessage(HRM_CHANNEL,
AntMesg.MESG_CHANNEL_ID_ID);
Log.d(TAG, "Requesting channel id id.");
}
setSensorState(Sensor.SensorState.CONNECTED);
int bpm = (int) antMessage[8] & 0xFF;
int bpm = (int) antMessage[10] & 0xFF;
Sensor.SensorData.Builder b = Sensor.SensorData.newBuilder()
.setValue(bpm)
.setState(Sensor.SensorState.SENDING);
@@ -127,9 +115,11 @@ public class AntDirectSensorManager extends AntSensorManager {
.build();
}
void handleChannelId(byte[] rawMessage) {
AntChannelIdMessage message = new AntChannelIdMessage(rawMessage);
deviceNumberHRM = message.getDeviceNumber();
void handleChannelId(byte[] antMessage) {
// Store the device id.
deviceNumberHRM =
(short) (((int) antMessage[3] & 0xFF |
((int) (antMessage[4] & 0xFF) << 8)) & 0xFFFF);
Log.i(TAG, "Found device id: " + deviceNumberHRM);
SharedPreferences prefs = context.getSharedPreferences(
@@ -139,31 +129,26 @@ public class AntDirectSensorManager extends AntSensorManager {
editor.commit();
}
private void handleMessageResponse(byte[] rawMessage) {
AntChannelResponseMessage message = new AntChannelResponseMessage(rawMessage);
switch (message.getMessageId()) {
case AntMesg.MESG_EVENT_ID:
if (message.getMessageCode() == AntDefine.EVENT_RX_SEARCH_TIMEOUT) {
// Search timeout
Log.w(TAG, "Search timed out. Unassigning channel.");
try {
getAntReceiver().ANTUnassignChannel((byte) 0);
} catch (AntInterfaceException e) {
Log.e(TAG, "ANT error unassigning channel", e);
}
setSensorState(Sensor.SensorState.DISCONNECTED);
}
break;
case AntMesg.MESG_UNASSIGN_CHANNEL_ID:
setSensorState(Sensor.SensorState.DISCONNECTED);
Log.i(TAG, "Disconnected from the sensor: " + getSensorState());
break;
private void handleMessageResponse(byte[] antMessage) {
if (antMessage[3] == AntMesg.MESG_EVENT_ID &&
antMessage[4] == AntDefine.EVENT_RX_SEARCH_TIMEOUT) {
// Search timeout
Log.w(TAG, "Search timed out. Unassigning channel.");
getAntReceiver().ANTUnassignChannel((byte) 0);
setSensorState(Sensor.SensorState.DISCONNECTED);
} else if (antMessage[3] == AntMesg.MESG_UNASSIGN_CHANNEL_ID) {
setSensorState(Sensor.SensorState.DISCONNECTED);
Log.i(TAG, "Disconnected from the sensor: " + getSensorState());
}
}
@Override protected void setupAntSensorChannels() {
setupAntSensorChannel(NETWORK_NUMBER,
/**
* Open a channel to the SRM head unit.
*/
@Override
public void setupChannel() {
super.setupChannel();
antChannelSetup(NETWORK_NUMBER,
HRM_CHANNEL,
deviceNumberHRM,
HEART_RATE_DEVICE_TYPE,
@@ -171,6 +156,7 @@ public class AntDirectSensorManager extends AntSensorManager {
CHANNEL_PERIOD,
RF_FREQUENCY,
(byte) 0);
setSensorState(Sensor.SensorState.CONNECTING);
}
public short getDeviceNumberHRM() {
@@ -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,15 +15,13 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.dsi.ant.AntDefine;
import com.dsi.ant.AntMesg;
import com.dsi.ant.exception.AntInterfaceException;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.maps.mytracks.R;
import com.dsi.ant.AntDefine;
import com.dsi.ant.AntMesg;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
@@ -82,10 +80,10 @@ public class AntSRMSensorManager extends AntSensorManager {
@Override
public void handleMessage(byte[] antMessage) {
// Parse channel number
byte receivedChannel = (byte) (antMessage[AntMesg.MESG_DATA_OFFSET]
byte recievedChannel = (byte) (antMessage[AntMesg.MESG_DATA_OFFSET]
& AntDefine.CHANNEL_NUMBER_MASK);
if (receivedChannel != channel) {
Log.d(TAG, "Unexpected channel: " + receivedChannel);
if (recievedChannel != channel) {
Log.d(MyTracksConstants.TAG, "Unexpected channel: " + recievedChannel);
return;
}
switch (antMessage[AntMesg.MESG_ID_OFFSET]) {
@@ -99,18 +97,15 @@ public class AntSRMSensorManager extends AntSensorManager {
handleChannelId(antMessage);
break;
default:
Log.e(TAG, "Unexpected message id: " + antMessage[3]);
Log.e(MyTracksConstants.TAG,
"Unexpected message id: " + antMessage[3]);
}
}
private void handleBroadcastData(byte[] antMessage) {
if (deviceId == WILDCARD) {
try {
Log.d(TAG, "Requesting channel id id.");
getAntReceiver().ANTRequestMessage(channel, AntMesg.MESG_CHANNEL_ID_ID);
} catch (AntInterfaceException e) {
Log.e(TAG, "Failed to request channel id id", e);
}
getAntReceiver().ANTRequestMessage(channel, AntMesg.MESG_CHANNEL_ID_ID);
Log.d(MyTracksConstants.TAG, "Requesting channel id id.");
}
setSensorState(Sensor.SensorState.CONNECTED);
switch(antMessage[MESSAGE_TYPE_INDEX]) {
@@ -121,14 +116,15 @@ public class AntSRMSensorManager extends AntSensorManager {
parseSensorData(antMessage);
break;
default:
Log.e(TAG, "Unexpected message type: " + antMessage[MESSAGE_TYPE_INDEX]);
Log.e(MyTracksConstants.TAG,
"Unexpected message type: " + antMessage[MESSAGE_TYPE_INDEX]);
}
}
private void handleChannelId(byte[] antMessage) {
// Store the device id.
deviceId = antMessage[3];
Log.i(TAG, "Found device id: " + deviceId);
Log.i(MyTracksConstants.TAG, "Found device id: " + deviceId);
SharedPreferences prefs = context.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, Context.MODE_PRIVATE);
@@ -141,34 +137,34 @@ public class AntSRMSensorManager extends AntSensorManager {
if (antMessage[3] == AntMesg.MESG_EVENT_ID
&& antMessage[4] == AntDefine.EVENT_RX_SEARCH_TIMEOUT) {
// Search timeout
Log.w(TAG, "Search timed out. Unassigning channel.");
try {
getAntReceiver().ANTUnassignChannel(channel);
} catch (AntInterfaceException e) {
Log.e(TAG, "Failed to unassign ANT channel", e);
}
Log.w(MyTracksConstants.TAG, "Search timed out. Unassigning channel.");
getAntReceiver().ANTUnassignChannel(channel);
setSensorState(Sensor.SensorState.DISCONNECTED);
} else if (antMessage[3] == AntMesg.MESG_UNASSIGN_CHANNEL_ID) {
setSensorState(Sensor.SensorState.DISCONNECTED);
Log.i(TAG, "Disconnected from the sensor: " + getSensorState());
Log.i(MyTracksConstants.TAG,
"Disconnected from the sensor: " + getSensorState());
}
}
private void parseSensorData(byte[] antMessage) {
if (antMessage.length != 11) {
Log.e(TAG, "Unexpected ant message length: " + antMessage.length);
Log.e(MyTracksConstants.TAG,
"Unexpected ant message length: " + antMessage.length);
return;
}
int newMessageId = antMessage[MESSAGE_ID_INDEX] & 0xFF;
if (lastMessageId == newMessageId) {
// Repeated message.
Log.i(TAG, String.format("SRM ignoring repeat: 0x%X", newMessageId));
Log.i(MyTracksConstants.TAG,
String.format("SRM ignoring repeat: 0x%X", newMessageId));
return;
}
if (newMessageId < lastMessageId) {
if (!(newMessageId < 20 && lastMessageId > 200)) {
Log.i(TAG, String.format("SRM ignoring repeat: 0x%X", newMessageId));
Log.i(MyTracksConstants.TAG,
String.format("SRM ignoring repeat: 0x%X", newMessageId));
return;
} // else assume the byte overflowed to 0.
}
@@ -211,10 +207,12 @@ public class AntSRMSensorManager extends AntSensorManager {
sensorData = builder.build();
}
/**
* Open a channel to the SRM head unit.
*/
@Override
protected void setupAntSensorChannels() {
lastMessageId = 0;
setupAntSensorChannel(NETWORK_NUMBER,
public void setupChannel() {
antChannelSetup(NETWORK_NUMBER,
channel,
deviceId,
DEVICE_TYPE,
@@ -222,5 +220,7 @@ public class AntSRMSensorManager extends AntSensorManager {
CHANNEL_PERIOD,
RF_FREQUENCY,
(byte) 0);
lastMessageId = 0;
setSensorState(Sensor.SensorState.CONNECTING);
}
}
@@ -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,57 +15,38 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.dsi.ant.AntDefine;
import com.dsi.ant.AntInterface;
import com.dsi.ant.AntInterfaceIntent;
import com.dsi.ant.AntMesg;
import com.dsi.ant.exception.AntInterfaceException;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.services.sensors.ant.AntStartupMessage;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
/**
* This is the common superclass for ANT-based sensors. It handles tasks which
* apply to the ANT framework as a whole, such as framework initialization and
* destruction. Subclasses are expected to handle the initialization and
* management of individual sensors.
*
* Implementation:
*
* The initialization process is somewhat complicated. This is due in part to
* the asynchronous nature of ANT Radio Service initialization, and in part due
* to an apparent bug in that service. The following is an overview of the
* initialization process.
*
* Initialization begins in {@link #setupChannel}, which is invoked by the
* {@link SensorManager} when track recording begins. {@link #setupChannel}
* asks the ANT Radio Service (via {@link AntInterface}) to start, using a
* {@link AntInterface.ServiceListener} to indicate when the service has
* connected. {@link #serviceConnected} claims and enables the Radio Service,
* and then resets it to a known state for our use. Completion of reset is
* indicated by receipt of a startup message (see {@link AntStartupMessage}).
* Once we've received that message, the ANT service is ready for use, and we
* can start sensor-specific initialization using
* {@link #setupAntSensorChannels}. The initialization of each sensor will
* usually result in a call to {@link #setupAntSensorChannel}.
* An abstract class for ANT+ based sensors.
*
* @author Sandor Dornbush
*/
public abstract class AntSensorManager extends SensorManager {
// ANT Service
public static final int EVENT_ANT_ENABLED = 1;
public static final int EVENT_ANT_DISABLED = 2;
// Pairing
protected static final short WILDCARD = 0;
private AntInterface antReceiver;
private boolean status;
// Flag to know if the ANT App was interrupted
// TODO: This code path is not used but probably should be.
private boolean antInterrupted;
@@ -76,29 +57,40 @@ public abstract class AntSensorManager extends SensorManager {
protected SensorDataSet sensorData;
protected Context context;
private static final boolean DEBUGGING = false;
/** Receives and logs all status ANT intents. */
private final BroadcastReceiver statusReceiver = new BroadcastReceiver() {
/**
* Receives all of the ANT intents and dispatches to the proper handler.
*/
private final BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String antAction = intent.getAction();
Log.i(TAG, "enter status onReceive" + antAction);
}
};
/** Receives all data ANT intents. */
private final BroadcastReceiver dataReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String antAction = intent.getAction();
Log.i(TAG, "enter data onReceive" + antAction);
Log.i(MyTracksConstants.TAG, "enter onReceive" + antAction);
if (antAction.equals(AntInterfaceIntent.ANT_ENABLED_ACTION)) {
Log.i(MyTracksConstants.TAG, "enter onReceive ANT_ENABLED_ACTION "
+ antAction);
handler.sendMessage(handler.obtainMessage(EVENT_ANT_ENABLED, 0));
}
if (antAction.equals(AntInterfaceIntent.ANT_DISABLED_ACTION)) {
Log.i(MyTracksConstants.TAG, "enter onReceive ANT_DISABLED_ACTION "
+ antAction);
handler.sendMessage(handler.obtainMessage(EVENT_ANT_DISABLED, 0));
}
if (antAction.equals(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION)) {
byte[] antMessage = intent.getByteArrayExtra(AntInterfaceIntent.ANT_MESSAGE);
byte[] antMessage =
intent.getByteArrayExtra(AntInterfaceIntent.ANT_MESSAGE);
if (DEBUGGING) {
Log.d(TAG, "Received RX message " + messageToString(antMessage));
StringBuilder sb =
new StringBuilder("ANT_RX_MESSAGE_ACTION Rx:");
for (int i = 0; i < antMessage.length; i++)
sb.append(String.format("[%X]]", (antMessage[i] & 0xFF)));
Log.d(MyTracksConstants.TAG, sb.toString());
}
handleMessage(antMessage);
@@ -107,39 +99,60 @@ public abstract class AntSensorManager extends SensorManager {
};
/**
* ANT uses this listener to tell us when it has bound to the ANT Radio
* Service. We can't start sending ANT commands until we've been notified
* (via this listener) that the Radio Service has connected.
*/
private AntInterface.ServiceListener antServiceListener = new AntInterface.ServiceListener() {
* Handler for all the ANT related events. The events will be handled only
* when we are in the ANT application main menu
**/
private Handler handler = new Handler() {
@Override
public void onServiceConnected() {
serviceConnected();
}
@Override
public void onServiceDisconnected() {
Log.d(TAG, "ANT interface reports disconnection");
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_ANT_ENABLED:
Log.i(MyTracksConstants.TAG,
"enter handleMessage ----EVENT_ANT_ENABLED");
break;
case EVENT_ANT_DISABLED:
Log.i(MyTracksConstants.TAG,
"enter handleMessage ----EVENT_ANT_DISABLED");
break;
}
}
};
public AntSensorManager(Context context) {
this.context = context;
// Need to enable the ANT if it is not enabled earlier
antReceiver = AntInterface.getInstance(context, null);
if (antReceiver == null) {
return;
}
status = antReceiver.isEnabled();
if (!status) {
// Make sure not to call AntInterface.enable() again, if it has been
// already called before
if (antInterrupted == false) {
status = antReceiver.enable();
if (!status) {
Log.e(MyTracksConstants.TAG, "Can not enable ANT interface");
} else {
Log.i(MyTracksConstants.TAG, "Powering on Radio");
}
} else {
Log.i(MyTracksConstants.TAG, "Radio already enabled");
}
}
}
@Override
public void onDestroy() {
Log.i(TAG, "destroying AntSensorManager");
context.unregisterReceiver(statusReceiver);
context.unregisterReceiver(dataReceiver);
try {
antReceiver.releaseInterface();
} catch (AntInterfaceException e) {
Log.e(TAG, "failed to release ANT interface", e);
}
antReceiver.destroy();
public void setupChannel() {
Log.i(MyTracksConstants.TAG, "Registering for ant intents.");
// Register for ANT intent broadcasts.
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(AntInterfaceIntent.ANT_ENABLED_ACTION);
intentFilter.addAction(AntInterfaceIntent.ANT_DISABLED_ACTION);
intentFilter.addAction(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION);
context.registerReceiver(receiver, intentFilter);
}
@Override
@@ -152,183 +165,64 @@ public abstract class AntSensorManager extends SensorManager {
return true;
}
public AntInterface getAntReceiver() {
return antReceiver;
}
public abstract void handleMessage(byte[] antMessage);
/**
* This is the interface used by the {@link SensorManager} to tell this
* class when to start. It handles initialization of the ANT framework,
* eventually resulting in sensor-specific initialization via
* {@link #setupAntSensorChannels}.
*/
@Override
protected final void setupChannel() {
// We handle this unpleasantly because the UI should've checked for ANT
// support before it even instantiated this class.
if (!AntInterface.hasAntSupport(context)) {
throw new IllegalStateException("device does not have ANT support");
}
// We register for ANT intents early because we want to have a record of
// the status intents in the log as we start up.
registerForAntIntents();
antReceiver = AntInterface.getInstance(context, antServiceListener);
if (antReceiver == null) {
Log.e(TAG, "Failed to get ANT Receiver");
return;
}
setSensorState(Sensor.SensorState.CONNECTING);
public void onDestroy() {
Log.i(MyTracksConstants.TAG, "Unregistering for ant intents.");
context.unregisterReceiver(receiver);
}
/**
* This method is invoked via the ServiceListener when we're connected to
* the ANT service. If we're just starting up, this is our first opportunity
* to initiate any ANT commands.
* Set up an ANT+ channel.
*
* @return True on success.
*/
private synchronized void serviceConnected() {
Log.d(TAG, "ANT service connected");
try {
if (!antReceiver.claimInterface()) {
Log.e(TAG, "failed to claim ANT interface");
return;
}
if (!antReceiver.isEnabled()) {
// Make sure not to call AntInterface.enable() again, if it has been
// already called before
if (antInterrupted == false) {
Log.i(TAG, "Powering on Radio");
antReceiver.enable();
}
} else {
Log.i(TAG, "Radio already enabled");
}
} catch (AntInterfaceException e) {
Log.e(TAG, "failed to enable ANT", e);
}
try {
// We expect this call to throw an exception due to a bug in the ANT
// Radio Service. It won't actually fail, though, as we'll get the
// startup message (see {@link AntStartupMessage}) one normally expects
// after a reset. Channel initialization can proceed once we receive
// that message.
antReceiver.ANTResetSystem();
} catch (AntInterfaceException e) {
Log.e(TAG, "failed to reset ANT (expected exception)", e);
}
}
/**
* Process a raw ANT message.
* @param antMessage the ANT message, including the size and message ID bytes
* @deprecated Use {@link #handleMessage(int, byte[])} instead.
*/
protected void handleMessage(byte[] antMessage) {
int len = antMessage[0];
if (len != antMessage.length - 2 || antMessage.length <= 2) {
Log.e(TAG, "Invalid message: " + messageToString(antMessage));
return;
}
byte messageId = antMessage[1];
// Arrays#copyOfRange doesn't exist??
byte[] messageData = new byte[antMessage.length - 2];
System.arraycopy(antMessage, 2, messageData, 0, antMessage.length - 2);
handleMessage(messageId, messageData);
}
/**
* Process a raw ANT message.
* @param messageId the message ID. See the ANT Message Protocol and Usage
* guide, section 9.3.
* @param messageData the ANT message, without the size and message ID bytes.
* @return true if this method has taken responsibility for the passed
* message; false otherwise.
*/
protected boolean handleMessage(byte messageId, byte[] messageData) {
if (messageId == AntMesg.MESG_STARTUP_MESG_ID) {
Log.d(TAG, String.format("Received startup message (reason %02x); initializing channel",
new AntStartupMessage(messageData).getMessage()));
setupAntSensorChannels();
return true;
}
return false;
}
/**
* Subclasses define this method to perform sensor-specific initialization.
* When this method is called, the ANT framework has been enabled, and is
* ready for use.
*/
protected abstract void setupAntSensorChannels();
/**
* Used by subclasses to set up an ANT channel for a single sensor. A given
* subclass may invoke this method multiple times if the subclass is
* responsible for more than one sensor.
*
* @return true on success
*/
protected boolean setupAntSensorChannel(byte networkNumber, byte channelNumber,
protected boolean antChannelSetup(byte networkNumber, byte channelNumber,
short deviceNumber, byte deviceType, byte txType, short channelPeriod,
byte radioFreq, byte proxSearch) {
try {
// Assign as slave channel on selected network (0 = public, 1 = ANT+, 2 =
// ANTFS)
antReceiver.ANTAssignChannel(channelNumber, AntDefine.PARAMETER_RX_NOT_TX, networkNumber);
antReceiver.ANTSetChannelId(channelNumber, deviceNumber, deviceType, txType);
antReceiver.ANTSetChannelPeriod(channelNumber, channelPeriod);
antReceiver.ANTSetChannelRFFreq(channelNumber, radioFreq);
// Disable high priority search
antReceiver.ANTSetChannelSearchTimeout(channelNumber, (byte) 0);
// Set search timeout to 30 seconds (low priority search))
antReceiver.ANTSetLowPriorityChannelSearchTimeout(channelNumber, (byte) 12);
if (deviceNumber == WILDCARD) {
// Configure proximity search, if using wild card search
antReceiver.ANTSetProximitySearch(channelNumber, proxSearch);
}
antReceiver.ANTOpenChannel(channelNumber);
return true;
} catch (AntInterfaceException e) {
Log.e(TAG, "failed to setup ANT channel", e);
// Assign as slave channel on selected network (0 = public, 1 = ANT+, 2 =
// ANTFS)
if (!antReceiver.ANTAssignChannel(channelNumber,
AntDefine.PARAMETER_RX_NOT_TX, networkNumber)) {
return false;
}
}
private void registerForAntIntents() {
Log.i(TAG, "Registering for ant intents.");
// Register for ANT intent broadcasts.
IntentFilter statusIntentFilter = new IntentFilter();
statusIntentFilter.addAction(AntInterfaceIntent.ANT_ENABLED_ACTION);
statusIntentFilter.addAction(AntInterfaceIntent.ANT_DISABLED_ACTION);
statusIntentFilter.addAction(AntInterfaceIntent.ANT_INTERFACE_CLAIMED_ACTION);
statusIntentFilter.addAction(AntInterfaceIntent.ANT_RESET_ACTION);
context.registerReceiver(statusReceiver, statusIntentFilter);
IntentFilter dataIntentFilter = new IntentFilter();
dataIntentFilter.addAction(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION);
context.registerReceiver(dataReceiver, dataIntentFilter);
}
private String messageToString(byte[] message) {
StringBuilder out = new StringBuilder();
for (byte b : message) {
out.append(String.format("%s%02x", (out.length() == 0 ? "" : " "), b));
if (!antReceiver.ANTSetChannelId(channelNumber, deviceNumber, deviceType,
txType)) {
return false;
}
return out.toString();
if (!antReceiver.ANTSetChannelPeriod(channelNumber, channelPeriod)) {
return false;
}
if (!antReceiver.ANTSetChannelRFFreq(channelNumber, radioFreq)) {
return false;
}
// Disable high priority search
if (!antReceiver.ANTSetChannelSearchTimeout(channelNumber, (byte) 0)) {
return false;
}
// Set search timeout to 30 seconds (low priority search))
if (!antReceiver.ANTSetLowPriorityChannelSearchTimeout(channelNumber, (byte) 12)) {
return false;
}
if (deviceNumber == WILDCARD) {
// Configure proximity search, if using wild card search
if (!antReceiver.ANTSetProximitySearch(channelNumber, proxSearch)) {
return false;
}
}
return !antReceiver.ANTOpenChannel(channelNumber);
}
public AntInterface getAntReceiver() {
return antReceiver;
}
}
@@ -16,8 +16,7 @@
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.content.Sensor;
import android.bluetooth.BluetoothAdapter;
@@ -86,7 +85,7 @@ public class BluetoothConnectionManager {
*/
private synchronized void setState(Sensor.SensorState state) {
// TODO pretty print this.
Log.d(TAG, "setState(" + state + ")");
Log.d(MyTracksConstants.TAG, "setState(" + state + ")");
this.state = state;
// Give the new state to the Handler so the UI Activity can update
@@ -105,7 +104,7 @@ public class BluetoothConnectionManager {
* in listening (server) mode. Called by the Activity onResume()
*/
public synchronized void start() {
Log.d(TAG, "BluetoothConnectionManager.start()");
Log.d(MyTracksConstants.TAG, "BluetoothConnectionManager.start()");
// Cancel any thread attempting to make a connection
if (connectThread != null) {
@@ -128,7 +127,7 @@ public class BluetoothConnectionManager {
* @param device The BluetoothDevice to connect
*/
public synchronized void connect(BluetoothDevice device) {
Log.d(TAG, "connect to: " + device);
Log.d(MyTracksConstants.TAG, "connect to: " + device);
// Cancel any thread attempting to make a connection
if (state == Sensor.SensorState.CONNECTING) {
@@ -158,7 +157,7 @@ public class BluetoothConnectionManager {
*/
public synchronized void connected(BluetoothSocket socket,
BluetoothDevice device) {
Log.d(TAG, "connected");
Log.d(MyTracksConstants.TAG, "connected");
// Cancel the thread that completed the connection
if (connectThread != null) {
@@ -190,7 +189,7 @@ public class BluetoothConnectionManager {
* Stop all threads
*/
public synchronized void stop() {
Log.d(TAG, "stop()");
Log.d(MyTracksConstants.TAG, "stop()");
if (connectThread != null) {
connectThread.cancel();
connectThread = null;
@@ -227,7 +226,7 @@ public class BluetoothConnectionManager {
*/
private void connectionFailed() {
setState(Sensor.SensorState.DISCONNECTED);
Log.i(TAG, "Bluetooth connection failed.");
Log.i(MyTracksConstants.TAG, "Bluetooth connection failed.");
}
/**
@@ -235,7 +234,7 @@ public class BluetoothConnectionManager {
*/
private void connectionLost() {
setState(Sensor.SensorState.DISCONNECTED);
Log.i(TAG, "Bluetooth connection lost.");
Log.i(MyTracksConstants.TAG, "Bluetooth connection lost.");
}
/**
@@ -256,7 +255,7 @@ public class BluetoothConnectionManager {
try {
tmp = getSocket();
} catch (IOException e) {
Log.e(TAG, "create() failed", e);
Log.e(MyTracksConstants.TAG, "create() failed", e);
}
socket = tmp;
}
@@ -269,22 +268,22 @@ public class BluetoothConnectionManager {
insecure.setAccessible(true);
return (BluetoothSocket) insecure.invoke(device, 1);
} catch (SecurityException e) {
Log.e(TAG, "Unable to get insecure connect.", e);
Log.e(MyTracksConstants.TAG, "Unable to get insecure connect.", e);
} catch (NoSuchMethodException e) {
Log.e(TAG, "Unable to get insecure connect.", e);
Log.e(MyTracksConstants.TAG, "Unable to get insecure connect.", e);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Unable to get insecure connect.", e);
Log.e(MyTracksConstants.TAG, "Unable to get insecure connect.", e);
} catch (IllegalAccessException e) {
Log.e(TAG, "Unable to get insecure connect.", e);
Log.e(MyTracksConstants.TAG, "Unable to get insecure connect.", e);
} catch (InvocationTargetException e) {
Log.e(TAG, "Unable to get insecure connect.", e);
Log.e(MyTracksConstants.TAG, "Unable to get insecure connect.", e);
}
return device.createRfcommSocketToServiceRecord(SPP_UUID);
}
@Override
public void run() {
Log.d(TAG, "BEGIN mConnectThread");
Log.d(MyTracksConstants.TAG, "BEGIN mConnectThread");
// Always cancel discovery because it will slow down a connection
adapter.cancelDiscovery();
@@ -300,7 +299,8 @@ public class BluetoothConnectionManager {
try {
socket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2);
Log.e(MyTracksConstants.TAG,
"unable to close() socket during connection failure", e2);
}
// Start the service over to restart listening mode
BluetoothConnectionManager.this.start();
@@ -320,7 +320,7 @@ public class BluetoothConnectionManager {
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
Log.e(MyTracksConstants.TAG, "close() of connect socket failed", e);
}
}
}
@@ -335,7 +335,7 @@ public class BluetoothConnectionManager {
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
Log.d(MyTracksConstants.TAG, "create ConnectedThread");
btSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
@@ -345,7 +345,7 @@ public class BluetoothConnectionManager {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
Log.e(MyTracksConstants.TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
@@ -354,7 +354,7 @@ public class BluetoothConnectionManager {
@Override
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
Log.i(MyTracksConstants.TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[parser.getFrameSize()];
int bytes;
int offset = 0;
@@ -383,10 +383,11 @@ public class BluetoothConnectionManager {
// re-align
offset = parser.getFrameSize() - index;
System.arraycopy(buffer, index, buffer, 0, offset);
Log.w(TAG, "Misaligned data, found new message at " + index + " recovering...");
Log.w(MyTracksConstants.TAG, "Misaligned data, found new message at " +
index + " recovering...");
continue;
}
Log.w(TAG, "Could not find valid data, dropping data");
Log.w(MyTracksConstants.TAG, "Could not find valid data, dropping data");
offset = 0;
continue;
}
@@ -397,7 +398,7 @@ public class BluetoothConnectionManager {
handler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
Log.e(MyTracksConstants.TAG, "disconnected", e);
connectionLost();
break;
}
@@ -416,7 +417,7 @@ public class BluetoothConnectionManager {
// Share the sent message back to the UI Activity
handler.obtainMessage(MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
Log.e(MyTracksConstants.TAG, "Exception during write", e);
}
}
@@ -424,7 +425,7 @@ public class BluetoothConnectionManager {
try {
btSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
Log.e(MyTracksConstants.TAG, "close() of connect socket failed", e);
}
}
}
@@ -15,8 +15,7 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.maps.mytracks.R;
@@ -51,7 +50,7 @@ public class BluetoothSensorManager extends SensorManager {
private Sensor.SensorDataSet sensorDataSet = null;
private MessageParser parser;
public BluetoothSensorManager(
Context context, MessageParser parser) {
this.context = context;
@@ -67,7 +66,7 @@ public class BluetoothSensorManager extends SensorManager {
}
private void setupSensor() {
Log.d(TAG, "setupSensor()");
Log.d(MyTracksConstants.TAG, "setupSensor()");
// Initialize the BluetoothSensorAdapter to perform bluetooth connections.
connectionManager = new BluetoothConnectionManager(messageHandler, parser);
@@ -79,7 +78,7 @@ public class BluetoothSensorManager extends SensorManager {
public void setupChannel() {
if (!isEnabled() || connectionManager == null) {
Log.w(TAG, "Disabled manager onStartTrack");
Log.w(MyTracksConstants.TAG, "Disabled manager onStartTrack");
return;
}
SharedPreferences prefs =
@@ -89,7 +88,7 @@ public class BluetoothSensorManager extends SensorManager {
if (address == null) {
return;
}
Log.w(TAG, "Connecting to bluetooth sensor: " + address);
Log.w(MyTracksConstants.TAG, "Connecting to bluetooth sensor: " + address);
// Get the BluetoothDevice object
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
@@ -103,7 +102,7 @@ public class BluetoothSensorManager extends SensorManager {
// already
if (connectionManager.getState() == Sensor.SensorState.NONE) {
// Start the Bluetooth sensor services
Log.w(TAG, "Disabled manager onStartTrack");
Log.w(MyTracksConstants.TAG, "Disabled manager onStartTrack");
connectionManager.start();
}
}
@@ -133,7 +132,7 @@ public class BluetoothSensorManager extends SensorManager {
switch (msg.what) {
case BluetoothConnectionManager.MESSAGE_STATE_CHANGE:
// TODO should we update the SensorManager state var?
Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
Log.i(MyTracksConstants.TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
break;
case BluetoothConnectionManager.MESSAGE_WRITE:
break;
@@ -142,14 +141,15 @@ public class BluetoothSensorManager extends SensorManager {
try {
readBuf = (byte[]) msg.obj;
sensorDataSet = parser.parseBuffer(readBuf);
Log.d(TAG, "MESSAGE_READ: " + sensorDataSet.toString());
Log.d(MyTracksConstants.TAG, "MESSAGE_READ: " + sensorDataSet.toString());
} catch (IllegalArgumentException iae) {
sensorDataSet = null;
Log.i(TAG, "Got bad sensor data: " + new String(readBuf, 0, readBuf.length),
Log.i(MyTracksConstants.TAG,
"Got bad sensor data: " + new String(readBuf, 0, readBuf.length),
iae);
} catch (RuntimeException re) {
sensorDataSet = null;
Log.i(TAG, "Unexpected exception on read.", re);
Log.i(MyTracksConstants.TAG, "Unexpected exception on read.", re);
}
break;
case BluetoothConnectionManager.MESSAGE_DEVICE_NAME:
@@ -15,14 +15,13 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.content.Sensor;
import java.util.Timer;
import java.util.TimerTask;
import android.util.Log;
import java.util.Timer;
import java.util.TimerTask;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.content.Sensor;
/**
* Manage the connection to a sensor.
@@ -42,7 +41,7 @@ public abstract class SensorManager {
public static final int RETRY_PERIOD = 30000;
private Sensor.SensorState sensorState = Sensor.SensorState.NONE;
private long sensorStateTimestamp = 0;
/**
@@ -51,17 +50,19 @@ public abstract class SensorManager {
private TimerTask checkSensorManager = new TimerTask() {
@Override
public void run() {
Log.i(TAG, "SensorManager state: " + getSensorState());
Log.i(MyTracksConstants.TAG,
"SensorManager state: " + getSensorState());
switch (getSensorState()) {
case CONNECTING:
long age = System.currentTimeMillis() - getSensorStateTimestamp();
if (age > 2 * RETRY_PERIOD) {
Log.i(TAG, "Retrying connecting SensorManager.");
Log.i(MyTracksConstants.TAG, "Retrying connecting SensorManager.");
setupChannel();
}
break;
case DISCONNECTED:
Log.i(TAG, "Re-registering disconnected SensorManager.");
Log.i(MyTracksConstants.TAG,
"Re-registering disconnected SensoManager.");
setupChannel();
break;
}
@@ -88,11 +89,7 @@ public abstract class SensorManager {
timer.schedule(checkSensorManager, RETRY_PERIOD, RETRY_PERIOD);
}
/**
* This method is used to set up any necessary connections to underlying
* sensor hardware.
*/
protected abstract void setupChannel();
public abstract void setupChannel();
public void shutdown() {
timer.cancel();
@@ -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,8 +15,7 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.maps.mytracks.R;
@@ -30,7 +29,9 @@ import android.util.Log;
* @author Sandor Dornbush
*/
public class SensorManagerFactory {
private SensorManagerFactory() {}
private SensorManagerFactory() {
}
/**
* Get a new sensor manager.
@@ -43,9 +44,9 @@ public class SensorManagerFactory {
if (prefs == null) {
return null;
}
String sensor = prefs.getString(context.getString(R.string.sensor_type_key), null);
Log.i(TAG, "Creating sensor of type: " + sensor);
Log.i(MyTracksConstants.TAG, "Creating sensor of type: " + sensor);
if (sensor == null) {
return null;
@@ -56,7 +57,7 @@ public class SensorManagerFactory {
} else if (sensor.equals(context.getString(R.string.zephyr_sensor_type))) {
return new ZephyrSensorManager(context);
} else {
Log.w(TAG, "Unable to find sensor type: " + sensor);
Log.w(MyTracksConstants.TAG, "Unable to find sensor type: " + sensor);
return null;
}
}
@@ -15,12 +15,11 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.content.Sensor;
import android.util.Log;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.content.Sensor;
/**
* An implementation of a SensorData parser for Zephyr HRM.
*
@@ -34,7 +33,7 @@ public class ZephyrMessageParser implements MessageParser {
for (int i = 0; i < buffer.length; i++) {
sb.append(String.format("%02X", buffer[i]));
}
Log.w(TAG, "Got zephyr data: " + sb);
Log.w(MyTracksConstants.TAG, "Got zephyr data: " + sb);
// The provided units are 1/16 strides per minute.
// TODO: Fix the cadence calculation.
// int cadence = SensorUtils.unsignedShortToInt(buffer, 56);
@@ -50,7 +49,7 @@ public class ZephyrMessageParser implements MessageParser {
.setCreationTime(System.currentTimeMillis())
.setHeartRate(b)
.build();
return sds;
}
@@ -1,56 +0,0 @@
/*
* 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.ant;
/**
* This class decodes and encapsulates an ANT Channel ID message.
* (ANT Message ID 0x51, Protocol & Usage guide v4.2 section 9.5.7.2)
*
* @author Matthew Simmons
*/
public class AntChannelIdMessage extends AntMessage {
private byte channelNumber;
private short deviceNumber;
private byte deviceTypeId;
private byte transmissionType;
public AntChannelIdMessage(byte[] messageData) {
channelNumber = messageData[0];
deviceNumber = decodeShort(messageData[1], messageData[2]);
deviceTypeId = messageData[3];
transmissionType = messageData[4];
}
/** Returns the channel number */
public byte getChannelNumber() {
return channelNumber;
}
/** Returns the device number */
public short getDeviceNumber() {
return deviceNumber;
}
/** Returns the device type */
public byte getDeviceTypeId() {
return deviceTypeId;
}
/** Returns the transmission type */
public byte getTransmissionType() {
return transmissionType;
}
}
@@ -1,49 +0,0 @@
/*
* 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.ant;
/**
* This class decodes and encapsulates an ANT Channel Response / Event message.
* (ANT Message ID 0x40, Protocol & Usage guide v4.2 section 9.5.6.1)
*
* @author Matthew Simmons
*/
public class AntChannelResponseMessage extends AntMessage {
private byte channelNumber;
private byte messageId;
private byte messageCode;
public AntChannelResponseMessage(byte[] messageData) {
channelNumber = messageData[0];
messageId = messageData[1];
messageCode = messageData[2];
}
/** Returns the channel number */
public byte getChannelNumber() {
return channelNumber;
}
/** Returns the ID of the message being responded to */
public byte getMessageId() {
return messageId;
}
/** Returns the code for a specific response or event */
public byte getMessageCode() {
return messageCode;
}
}
@@ -1,32 +0,0 @@
/*
* 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.ant;
/**
* This is a common superclass for ANT message subclasses.
*
* @author Matthew Simmons
*/
public class AntMessage {
protected AntMessage() {}
/** Build a short value from its constituent bytes */
protected static short decodeShort(byte b0, byte b1) {
short value = b0;
value |= ((short) b1) << 8;
return value;
}
}
@@ -1,35 +0,0 @@
/*
* 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.ant;
/**
* This class decodes and encapsulates an ANT Startup message.
* (ANT Message ID 0x6f, Protocol & Usage guide v4.2 section 9.5.3.1)
*
* @author Matthew Simmons
*/
public class AntStartupMessage extends AntMessage {
private byte message;
public AntStartupMessage(byte[] messageData) {
message = messageData[0];
}
/** Returns the cause of the startup */
public byte getMessage() {
return message;
}
}
@@ -1,35 +0,0 @@
/*
* 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.ant;
import com.dsi.ant.AntInterface;
import android.content.Context;
/**
* Utility methods for ANT functionality.
*
* Prefer use of this class to importing DSI ANT classes into code outside of
* the sensors package.
*/
public class AntUtils {
private AntUtils() {}
/** Returns true if this device supports ANT sensors. */
public static boolean hasAntSupport(Context context) {
return AntInterface.hasAntSupport(context);
}
}
@@ -17,7 +17,6 @@
package com.google.android.apps.mytracks.stats;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.MyTracksSettings;
import android.location.Location;
import android.util.Log;
@@ -90,9 +89,6 @@ public class TripStatisticsBuilder {
*/
private long totalLocations = 0;
private int minRecordingDistance =
MyTracksSettings.DEFAULT_MIN_RECORDING_DISTANCE;
/**
* Creates a new trip starting at the given time.
*
@@ -150,7 +146,7 @@ public class TripStatisticsBuilder {
// Don't do anything if we didn't move since last fix:
double distance = lastLocation.distanceTo(currentLocation);
if (distance < minRecordingDistance &&
if (distance < MyTracksConstants.MAX_NO_MOVEMENT_DISTANCE &&
currentSpeed < MyTracksConstants.MAX_NO_MOVEMENT_SPEED) {
lastLocation = currentLocation;
return false;
@@ -363,8 +359,4 @@ public class TripStatisticsBuilder {
// Take a snapshot - we don't want anyone messing with our internals
return new TripStatistics(data);
}
public void setMinRecordingDistance(int minRecordingDistance) {
this.minRecordingDistance = minRecordingDistance;
}
}
@@ -106,22 +106,6 @@ public class ApiFeatures {
public boolean hasStrictMode() {
return getApiLevel() >= 9;
}
public boolean isAudioFocusSupported() {
return getApiLevel() >= 8;
}
/**
* There's a bug (#1587) in Cupcake and Donut which prevents you from
* using a SQLiteQueryBuilder twice. That is, if you call buildQuery
* on a given instance (to log the statement for debugging), and then
* call query on the same instance to make it actually do the query,
* it'll regenerate the query for the second call, and will screw it
* up. Specifically, it'll add extra parens which don't belong.
*/
public boolean canReuseSQLiteQueryBuilder() {
return getApiLevel() > 4;
}
// Visible for testing.
protected int getApiLevel() {
@@ -58,7 +58,7 @@ public class ChartURLGenerator {
}
return getChartUrl(distances, elevations, track,
context.getString(R.string.elevation_label), metricUnits);
context.getString(R.string.elevation_label), metricUnits, true);
}
/**
@@ -70,10 +70,11 @@ public class ChartURLGenerator {
* @param track The track for this chart
* @param title The title for the chart
* @param metricUnits Should the data be displayed in metric units
* @param escapePipe Should the pipe character be escaped
*/
public static String getChartUrl(
Vector<Double> distances, Vector<Double> elevations,
Track track, String title, boolean metricUnits) {
Track track, String title, boolean metricUnits, boolean escapePipe) {
if (distances == null || elevations == null || track == null) {
return null;
}
@@ -124,7 +125,9 @@ public class ChartURLGenerator {
sb.append(',');
sb.append(xInterval);
sb.append("|1,");
// This is an ugly hack. We really want a pipe but we must double escape it.
sb.append(escapePipe ? "%257C" : "|");
sb.append("1,");
sb.append(effectiveMinY);
sb.append(',');
sb.append(effectiveMaxY);
@@ -15,16 +15,11 @@
*/
package com.google.android.apps.mytracks.util;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.SharedPreferences.Editor;
import android.os.HandlerThread;
import android.util.Log;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* The Cupcake (API level 3) specific implementation of the
@@ -38,38 +33,19 @@ public class CupcakePlatformAdapter implements ApiPlatformAdapter {
public void startForeground(Service service,
NotificationManager notificationManager, int id,
Notification notification) {
setServiceForeground(service, true);
service.setForeground(true);
notificationManager.notify(id, notification);
}
@Override
public void stopForeground(Service service,
NotificationManager notificationManager, int id) {
setServiceForeground(service, false);
service.setForeground(false);
if (id != -1) {
notificationManager.cancel(id);
}
}
private void setServiceForeground(Service service, boolean foreground) {
// setForeground has been completely removed in API level 11, so we use reflection.
try {
Method setForegroundMethod = Service.class.getMethod("setForeground", boolean.class);
setForegroundMethod.invoke(service, foreground);
} catch (SecurityException e) {
Log.e(TAG, "Unable to set service foreground state", e);
} catch (NoSuchMethodException e) {
Log.e(TAG, "Unable to set service foreground state", e);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Unable to set service foreground state", e);
} catch (IllegalAccessException e) {
Log.e(TAG, "Unable to set service foreground state", e);
} catch (InvocationTargetException e) {
Log.e(TAG, "Unable to set service foreground state", e);
}
}
@Override
public boolean stopHandlerThread(HandlerThread handlerThread) {
// Do nothing, as Cupcake doesn't provide quit().

Some files were not shown because too many files have changed in this diff Show More