Browse Source

Initial Import. Version 2.0

Carlos Mogas da Silva 9 years ago
commit
fbbd2673ff
69 changed files with 2994 additions and 0 deletions
  1. 8
    0
      .classpath
  2. 2
    0
      .gitignore
  3. 33
    0
      .project
  4. 3
    0
      .settings/org.eclipse.core.resources.prefs
  5. 22
    0
      AndroidManifest.xml
  6. BIN
      bin/Farmacias.apk
  7. BIN
      bin/classes.dex
  8. BIN
      bin/resources.ap_
  9. 13
    0
      default.properties
  10. 339
    0
      gpl-2.0.txt
  11. BIN
      libs/admob-sdk-android.jar
  12. BIN
      res/drawable-hdpi/dialog.9.png
  13. BIN
      res/drawable-hdpi/list_location.9.png
  14. BIN
      res/drawable-mdpi/arrow.png
  15. BIN
      res/drawable-mdpi/button_normal.9.png
  16. BIN
      res/drawable-mdpi/button_pressed.9.png
  17. BIN
      res/drawable-mdpi/compass_background.png
  18. BIN
      res/drawable-mdpi/compass_needle.png
  19. BIN
      res/drawable-mdpi/copy.png
  20. BIN
      res/drawable-mdpi/droid.png
  21. BIN
      res/drawable-mdpi/gps.png
  22. 4
    0
      res/drawable-mdpi/gps_fix.xml
  23. BIN
      res/drawable-mdpi/gps_fix1.png
  24. BIN
      res/drawable-mdpi/icon.png
  25. BIN
      res/drawable-mdpi/icon_call.png
  26. BIN
      res/drawable-mdpi/icon_car.png
  27. BIN
      res/drawable-mdpi/icon_details.png
  28. 7
    0
      res/drawable-mdpi/network_fix.xml
  29. BIN
      res/drawable-mdpi/network_fix1.png
  30. BIN
      res/drawable-mdpi/network_fix2.png
  31. BIN
      res/drawable-mdpi/network_fix3.png
  32. BIN
      res/drawable-mdpi/pin_off.png
  33. BIN
      res/drawable-mdpi/pin_on.png
  34. BIN
      res/drawable-mdpi/refresh.png
  35. BIN
      res/drawable-mdpi/status_off.png
  36. BIN
      res/drawable-mdpi/status_on.png
  37. 8
    0
      res/layout/about.xml
  38. 28
    0
      res/layout/list.xml
  39. 15
    0
      res/layout/list_row.xml
  40. 10
    0
      res/layout/map.xml
  41. 11
    0
      res/layout/mylocation_balloon.xml
  42. 76
    0
      res/layout/pharmacy_balloon.xml
  43. 157
    0
      res/layout/pharmacyinfo.xml
  44. 42
    0
      res/values-en/strings.xml
  45. 42
    0
      res/values-pt/strings.xml
  46. 10
    0
      res/values/attrs.xml
  47. 6
    0
      res/xml/dialog_button.xml
  48. 15
    0
      res/xml/preferences.xml
  49. 23
    0
      src/org/r3pek/pharmacies/ConfigValues.java
  50. 54
    0
      src/org/r3pek/pharmacies/GetPositionOverlay.java
  51. 161
    0
      src/org/r3pek/pharmacies/MyPositionOverlay.java
  52. 18
    0
      src/org/r3pek/pharmacies/MyPreferences.java
  53. 166
    0
      src/org/r3pek/pharmacies/PharmaciesOverlay.java
  54. 91
    0
      src/org/r3pek/pharmacies/Pharmacy.java
  55. 169
    0
      src/org/r3pek/pharmacies/PharmacyInfo.java
  56. 148
    0
      src/org/r3pek/pharmacies/PharmacyList.java
  57. 53
    0
      src/org/r3pek/pharmacies/PharmacyListSimpleAdapter.java
  58. 324
    0
      src/org/r3pek/pharmacies/ViewOnMap.java
  59. 111
    0
      src/org/r3pek/pharmacies/XMLParserHandler.java
  60. 121
    0
      src/org/r3pek/pharmacies/utils/GeoUtils.java
  61. 19
    0
      src/org/r3pek/pharmacies/utils/GlobalVars.java
  62. 9
    0
      src/org/r3pek/pharmacies/utils/OnPositionChangeListener.java
  63. 175
    0
      src/org/r3pek/pharmacies/utils/Positioner.java
  64. 97
    0
      src/org/r3pek/pharmacies/widgets/Arrow.java
  65. 101
    0
      src/org/r3pek/pharmacies/widgets/Compass.java
  66. 5
    0
      src/org/r3pek/pharmacies/widgets/ImageOrientationSensor.java
  67. 48
    0
      src/org/r3pek/pharmacies/widgets/ImageRotater.java
  68. 147
    0
      src/org/r3pek/pharmacies/widgets/ScrollTextView.java
  69. 103
    0
      src/org/r3pek/pharmacies/widgets/SeekBarPreference.java

+ 8
- 0
.classpath View File

@@ -0,0 +1,8 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<classpath>
3
+	<classpathentry kind="src" path="src"/>
4
+	<classpathentry kind="src" path="gen"/>
5
+	<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
6
+	<classpathentry kind="lib" path="libs/admob-sdk-android.jar"/>
7
+	<classpathentry kind="output" path="bin"/>
8
+</classpath>

+ 2
- 0
.gitignore View File

@@ -0,0 +1,2 @@
1
+/gen
2
+/bin

+ 33
- 0
.project View File

@@ -0,0 +1,33 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<projectDescription>
3
+	<name>Farmacias</name>
4
+	<comment></comment>
5
+	<projects>
6
+	</projects>
7
+	<buildSpec>
8
+		<buildCommand>
9
+			<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
10
+			<arguments>
11
+			</arguments>
12
+		</buildCommand>
13
+		<buildCommand>
14
+			<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
15
+			<arguments>
16
+			</arguments>
17
+		</buildCommand>
18
+		<buildCommand>
19
+			<name>org.eclipse.jdt.core.javabuilder</name>
20
+			<arguments>
21
+			</arguments>
22
+		</buildCommand>
23
+		<buildCommand>
24
+			<name>com.android.ide.eclipse.adt.ApkBuilder</name>
25
+			<arguments>
26
+			</arguments>
27
+		</buildCommand>
28
+	</buildSpec>
29
+	<natures>
30
+		<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
31
+		<nature>org.eclipse.jdt.core.javanature</nature>
32
+	</natures>
33
+</projectDescription>

+ 3
- 0
.settings/org.eclipse.core.resources.prefs View File

@@ -0,0 +1,3 @@
1
+#Thu Apr 15 12:30:11 WEST 2010
2
+eclipse.preferences.version=1
3
+encoding/<project>=UTF-8

+ 22
- 0
AndroidManifest.xml View File

@@ -0,0 +1,22 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+      package="org.r3pek.pharmacies" android:versionCode="9" android:versionName="2.0">
4
+    <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="false">
5
+    <activity android:name="MyPreferences"></activity>
6
+    <activity android:name="PharmacyList"></activity>
7
+	<activity android:name="PharmacyInfo"></activity>
8
+	<activity android:label="@string/app_name" android:name="ViewOnMap">
9
+            <intent-filter>
10
+                <action android:name="android.intent.action.MAIN" />
11
+                <category android:name="android.intent.category.LAUNCHER" />
12
+            </intent-filter>
13
+	</activity>
14
+	<uses-library android:name="com.google.android.maps" />
15
+	<meta-data android:value="a14be6d1c69912b" android:name="ADMOB_PUBLISHER_ID"/>
16
+</application>
17
+<uses-sdk android:minSdkVersion="3"/>
18
+<uses-permission android:name="android.permission.INTERNET"></uses-permission>
19
+<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
20
+<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"></uses-permission>
21
+<supports-screens android:smallScreens="true" android:normalScreens="true" android:resizeable="true" android:largeScreens="true" android:anyDensity="false"></supports-screens>
22
+</manifest> 

BIN
bin/Farmacias.apk View File


BIN
bin/classes.dex View File


BIN
bin/resources.ap_ View File


+ 13
- 0
default.properties View File

@@ -0,0 +1,13 @@
1
+# This file is automatically generated by Android Tools.
2
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3
+# 
4
+# This file must be checked in Version Control Systems.
5
+# 
6
+# To customize properties used by the Ant build system use,
7
+# "build.properties", and override values to adapt the script to your
8
+# project structure.
9
+
10
+# Indicates whether an apk should be generated for each density.
11
+split.density=false
12
+# Project target.
13
+target=Google Inc.:Google APIs:4

+ 339
- 0
gpl-2.0.txt View File

@@ -0,0 +1,339 @@
1
+                    GNU GENERAL PUBLIC LICENSE
2
+                       Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+                            Preamble
10
+
11
+  The licenses for most software are designed to take away your
12
+freedom to share and change it.  By contrast, the GNU General Public
13
+License is intended to guarantee your freedom to share and change free
14
+software--to make sure the software is free for all its users.  This
15
+General Public License applies to most of the Free Software
16
+Foundation's software and to any other program whose authors commit to
17
+using it.  (Some other Free Software Foundation software is covered by
18
+the GNU Lesser General Public License instead.)  You can apply it to
19
+your programs, too.
20
+
21
+  When we speak of free software, we are referring to freedom, not
22
+price.  Our General Public Licenses are designed to make sure that you
23
+have the freedom to distribute copies of free software (and charge for
24
+this service if you wish), that you receive source code or can get it
25
+if you want it, that you can change the software or use pieces of it
26
+in new free programs; and that you know you can do these things.
27
+
28
+  To protect your rights, we need to make restrictions that forbid
29
+anyone to deny you these rights or to ask you to surrender the rights.
30
+These restrictions translate to certain responsibilities for you if you
31
+distribute copies of the software, or if you modify it.
32
+
33
+  For example, if you distribute copies of such a program, whether
34
+gratis or for a fee, you must give the recipients all the rights that
35
+you have.  You must make sure that they, too, receive or can get the
36
+source code.  And you must show them these terms so they know their
37
+rights.
38
+
39
+  We protect your rights with two steps: (1) copyright the software, and
40
+(2) offer you this license which gives you legal permission to copy,
41
+distribute and/or modify the software.
42
+
43
+  Also, for each author's protection and ours, we want to make certain
44
+that everyone understands that there is no warranty for this free
45
+software.  If the software is modified by someone else and passed on, we
46
+want its recipients to know that what they have is not the original, so
47
+that any problems introduced by others will not reflect on the original
48
+authors' reputations.
49
+
50
+  Finally, any free program is threatened constantly by software
51
+patents.  We wish to avoid the danger that redistributors of a free
52
+program will individually obtain patent licenses, in effect making the
53
+program proprietary.  To prevent this, we have made it clear that any
54
+patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+  The precise terms and conditions for copying, distribution and
57
+modification follow.
58
+
59
+                    GNU GENERAL PUBLIC LICENSE
60
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+  0. This License applies to any program or other work which contains
63
+a notice placed by the copyright holder saying it may be distributed
64
+under the terms of this General Public License.  The "Program", below,
65
+refers to any such program or work, and a "work based on the Program"
66
+means either the Program or any derivative work under copyright law:
67
+that is to say, a work containing the Program or a portion of it,
68
+either verbatim or with modifications and/or translated into another
69
+language.  (Hereinafter, translation is included without limitation in
70
+the term "modification".)  Each licensee is addressed as "you".
71
+
72
+Activities other than copying, distribution and modification are not
73
+covered by this License; they are outside its scope.  The act of
74
+running the Program is not restricted, and the output from the Program
75
+is covered only if its contents constitute a work based on the
76
+Program (independent of having been made by running the Program).
77
+Whether that is true depends on what the Program does.
78
+
79
+  1. You may copy and distribute verbatim copies of the Program's
80
+source code as you receive it, in any medium, provided that you
81
+conspicuously and appropriately publish on each copy an appropriate
82
+copyright notice and disclaimer of warranty; keep intact all the
83
+notices that refer to this License and to the absence of any warranty;
84
+and give any other recipients of the Program a copy of this License
85
+along with the Program.
86
+
87
+You may charge a fee for the physical act of transferring a copy, and
88
+you may at your option offer warranty protection in exchange for a fee.
89
+
90
+  2. You may modify your copy or copies of the Program or any portion
91
+of it, thus forming a work based on the Program, and copy and
92
+distribute such modifications or work under the terms of Section 1
93
+above, provided that you also meet all of these conditions:
94
+
95
+    a) You must cause the modified files to carry prominent notices
96
+    stating that you changed the files and the date of any change.
97
+
98
+    b) You must cause any work that you distribute or publish, that in
99
+    whole or in part contains or is derived from the Program or any
100
+    part thereof, to be licensed as a whole at no charge to all third
101
+    parties under the terms of this License.
102
+
103
+    c) If the modified program normally reads commands interactively
104
+    when run, you must cause it, when started running for such
105
+    interactive use in the most ordinary way, to print or display an
106
+    announcement including an appropriate copyright notice and a
107
+    notice that there is no warranty (or else, saying that you provide
108
+    a warranty) and that users may redistribute the program under
109
+    these conditions, and telling the user how to view a copy of this
110
+    License.  (Exception: if the Program itself is interactive but
111
+    does not normally print such an announcement, your work based on
112
+    the Program is not required to print an announcement.)
113
+
114
+These requirements apply to the modified work as a whole.  If
115
+identifiable sections of that work are not derived from the Program,
116
+and can be reasonably considered independent and separate works in
117
+themselves, then this License, and its terms, do not apply to those
118
+sections when you distribute them as separate works.  But when you
119
+distribute the same sections as part of a whole which is a work based
120
+on the Program, the distribution of the whole must be on the terms of
121
+this License, whose permissions for other licensees extend to the
122
+entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+Thus, it is not the intent of this section to claim rights or contest
125
+your rights to work written entirely by you; rather, the intent is to
126
+exercise the right to control the distribution of derivative or
127
+collective works based on the Program.
128
+
129
+In addition, mere aggregation of another work not based on the Program
130
+with the Program (or with a work based on the Program) on a volume of
131
+a storage or distribution medium does not bring the other work under
132
+the scope of this License.
133
+
134
+  3. You may copy and distribute the Program (or a work based on it,
135
+under Section 2) in object code or executable form under the terms of
136
+Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+    a) Accompany it with the complete corresponding machine-readable
139
+    source code, which must be distributed under the terms of Sections
140
+    1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+    b) Accompany it with a written offer, valid for at least three
143
+    years, to give any third party, for a charge no more than your
144
+    cost of physically performing source distribution, a complete
145
+    machine-readable copy of the corresponding source code, to be
146
+    distributed under the terms of Sections 1 and 2 above on a medium
147
+    customarily used for software interchange; or,
148
+
149
+    c) Accompany it with the information you received as to the offer
150
+    to distribute corresponding source code.  (This alternative is
151
+    allowed only for noncommercial distribution and only if you
152
+    received the program in object code or executable form with such
153
+    an offer, in accord with Subsection b above.)
154
+
155
+The source code for a work means the preferred form of the work for
156
+making modifications to it.  For an executable work, complete source
157
+code means all the source code for all modules it contains, plus any
158
+associated interface definition files, plus the scripts used to
159
+control compilation and installation of the executable.  However, as a
160
+special exception, the source code distributed need not include
161
+anything that is normally distributed (in either source or binary
162
+form) with the major components (compiler, kernel, and so on) of the
163
+operating system on which the executable runs, unless that component
164
+itself accompanies the executable.
165
+
166
+If distribution of executable or object code is made by offering
167
+access to copy from a designated place, then offering equivalent
168
+access to copy the source code from the same place counts as
169
+distribution of the source code, even though third parties are not
170
+compelled to copy the source along with the object code.
171
+
172
+  4. You may not copy, modify, sublicense, or distribute the Program
173
+except as expressly provided under this License.  Any attempt
174
+otherwise to copy, modify, sublicense or distribute the Program is
175
+void, and will automatically terminate your rights under this License.
176
+However, parties who have received copies, or rights, from you under
177
+this License will not have their licenses terminated so long as such
178
+parties remain in full compliance.
179
+
180
+  5. You are not required to accept this License, since you have not
181
+signed it.  However, nothing else grants you permission to modify or
182
+distribute the Program or its derivative works.  These actions are
183
+prohibited by law if you do not accept this License.  Therefore, by
184
+modifying or distributing the Program (or any work based on the
185
+Program), you indicate your acceptance of this License to do so, and
186
+all its terms and conditions for copying, distributing or modifying
187
+the Program or works based on it.
188
+
189
+  6. Each time you redistribute the Program (or any work based on the
190
+Program), the recipient automatically receives a license from the
191
+original licensor to copy, distribute or modify the Program subject to
192
+these terms and conditions.  You may not impose any further
193
+restrictions on the recipients' exercise of the rights granted herein.
194
+You are not responsible for enforcing compliance by third parties to
195
+this License.
196
+
197
+  7. If, as a consequence of a court judgment or allegation of patent
198
+infringement or for any other reason (not limited to patent issues),
199
+conditions are imposed on you (whether by court order, agreement or
200
+otherwise) that contradict the conditions of this License, they do not
201
+excuse you from the conditions of this License.  If you cannot
202
+distribute so as to satisfy simultaneously your obligations under this
203
+License and any other pertinent obligations, then as a consequence you
204
+may not distribute the Program at all.  For example, if a patent
205
+license would not permit royalty-free redistribution of the Program by
206
+all those who receive copies directly or indirectly through you, then
207
+the only way you could satisfy both it and this License would be to
208
+refrain entirely from distribution of the Program.
209
+
210
+If any portion of this section is held invalid or unenforceable under
211
+any particular circumstance, the balance of the section is intended to
212
+apply and the section as a whole is intended to apply in other
213
+circumstances.
214
+
215
+It is not the purpose of this section to induce you to infringe any
216
+patents or other property right claims or to contest validity of any
217
+such claims; this section has the sole purpose of protecting the
218
+integrity of the free software distribution system, which is
219
+implemented by public license practices.  Many people have made
220
+generous contributions to the wide range of software distributed
221
+through that system in reliance on consistent application of that
222
+system; it is up to the author/donor to decide if he or she is willing
223
+to distribute software through any other system and a licensee cannot
224
+impose that choice.
225
+
226
+This section is intended to make thoroughly clear what is believed to
227
+be a consequence of the rest of this License.
228
+
229
+  8. If the distribution and/or use of the Program is restricted in
230
+certain countries either by patents or by copyrighted interfaces, the
231
+original copyright holder who places the Program under this License
232
+may add an explicit geographical distribution limitation excluding
233
+those countries, so that distribution is permitted only in or among
234
+countries not thus excluded.  In such case, this License incorporates
235
+the limitation as if written in the body of this License.
236
+
237
+  9. The Free Software Foundation may publish revised and/or new versions
238
+of the General Public License from time to time.  Such new versions will
239
+be similar in spirit to the present version, but may differ in detail to
240
+address new problems or concerns.
241
+
242
+Each version is given a distinguishing version number.  If the Program
243
+specifies a version number of this License which applies to it and "any
244
+later version", you have the option of following the terms and conditions
245
+either of that version or of any later version published by the Free
246
+Software Foundation.  If the Program does not specify a version number of
247
+this License, you may choose any version ever published by the Free Software
248
+Foundation.
249
+
250
+  10. If you wish to incorporate parts of the Program into other free
251
+programs whose distribution conditions are different, write to the author
252
+to ask for permission.  For software which is copyrighted by the Free
253
+Software Foundation, write to the Free Software Foundation; we sometimes
254
+make exceptions for this.  Our decision will be guided by the two goals
255
+of preserving the free status of all derivatives of our free software and
256
+of promoting the sharing and reuse of software generally.
257
+
258
+                            NO WARRANTY
259
+
260
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
262
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
266
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
267
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+REPAIR OR CORRECTION.
269
+
270
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+POSSIBILITY OF SUCH DAMAGES.
279
+
280
+                     END OF TERMS AND CONDITIONS
281
+
282
+            How to Apply These Terms to Your New Programs
283
+
284
+  If you develop a new program, and you want it to be of the greatest
285
+possible use to the public, the best way to achieve this is to make it
286
+free software which everyone can redistribute and change under these terms.
287
+
288
+  To do so, attach the following notices to the program.  It is safest
289
+to attach them to the start of each source file to most effectively
290
+convey the exclusion of warranty; and each file should have at least
291
+the "copyright" line and a pointer to where the full notice is found.
292
+
293
+    <one line to give the program's name and a brief idea of what it does.>
294
+    Copyright (C) <year>  <name of author>
295
+
296
+    This program is free software; you can redistribute it and/or modify
297
+    it under the terms of the GNU General Public License as published by
298
+    the Free Software Foundation; either version 2 of the License, or
299
+    (at your option) any later version.
300
+
301
+    This program is distributed in the hope that it will be useful,
302
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
304
+    GNU General Public License for more details.
305
+
306
+    You should have received a copy of the GNU General Public License along
307
+    with this program; if not, write to the Free Software Foundation, Inc.,
308
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+Also add information on how to contact you by electronic and paper mail.
311
+
312
+If the program is interactive, make it output a short notice like this
313
+when it starts in an interactive mode:
314
+
315
+    Gnomovision version 69, Copyright (C) year name of author
316
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+    This is free software, and you are welcome to redistribute it
318
+    under certain conditions; type `show c' for details.
319
+
320
+The hypothetical commands `show w' and `show c' should show the appropriate
321
+parts of the General Public License.  Of course, the commands you use may
322
+be called something other than `show w' and `show c'; they could even be
323
+mouse-clicks or menu items--whatever suits your program.
324
+
325
+You should also get your employer (if you work as a programmer) or your
326
+school, if any, to sign a "copyright disclaimer" for the program, if
327
+necessary.  Here is a sample; alter the names:
328
+
329
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+  <signature of Ty Coon>, 1 April 1989
333
+  Ty Coon, President of Vice
334
+
335
+This General Public License does not permit incorporating your program into
336
+proprietary programs.  If your program is a subroutine library, you may
337
+consider it more useful to permit linking proprietary applications with the
338
+library.  If this is what you want to do, use the GNU Lesser General
339
+Public License instead of this License.

BIN
libs/admob-sdk-android.jar View File


BIN
res/drawable-hdpi/dialog.9.png View File


BIN
res/drawable-hdpi/list_location.9.png View File


BIN
res/drawable-mdpi/arrow.png View File


BIN
res/drawable-mdpi/button_normal.9.png View File


BIN
res/drawable-mdpi/button_pressed.9.png View File


BIN
res/drawable-mdpi/compass_background.png View File


BIN
res/drawable-mdpi/compass_needle.png View File


BIN
res/drawable-mdpi/copy.png View File


BIN
res/drawable-mdpi/droid.png View File


BIN
res/drawable-mdpi/gps.png View File


+ 4
- 0
res/drawable-mdpi/gps_fix.xml View File

@@ -0,0 +1,4 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<level-list xmlns:android="http://schemas.android.com/apk/res/android">
3
+    <item android:maxLevel="0" android:drawable="@drawable/gps_fix1"/>
4
+</level-list>

BIN
res/drawable-mdpi/gps_fix1.png View File


BIN
res/drawable-mdpi/icon.png View File


BIN
res/drawable-mdpi/icon_call.png View File


BIN
res/drawable-mdpi/icon_car.png View File


BIN
res/drawable-mdpi/icon_details.png View File


+ 7
- 0
res/drawable-mdpi/network_fix.xml View File

@@ -0,0 +1,7 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<level-list xmlns:android="http://schemas.android.com/apk/res/android">
3
+    <item android:maxLevel="0" android:drawable="@drawable/network_fix1"/>
4
+    <item android:maxLevel="1" android:drawable="@drawable/network_fix2"/>
5
+    <item android:maxLevel="2" android:drawable="@drawable/network_fix3"/>
6
+    <item android:maxLevel="3" android:drawable="@drawable/network_fix2"/>
7
+</level-list>

BIN
res/drawable-mdpi/network_fix1.png View File


BIN
res/drawable-mdpi/network_fix2.png View File


BIN
res/drawable-mdpi/network_fix3.png View File


BIN
res/drawable-mdpi/pin_off.png View File


BIN
res/drawable-mdpi/pin_on.png View File


BIN
res/drawable-mdpi/refresh.png View File


BIN
res/drawable-mdpi/status_off.png View File


BIN
res/drawable-mdpi/status_on.png View File


+ 8
- 0
res/layout/about.xml View File

@@ -0,0 +1,8 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+
3
+<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:id="@+id/aboutRoot">
4
+<LinearLayout android:id="@+id/LinearLayout02" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center" android:layout_width="fill_parent"><ImageView android:id="@+id/ImageView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></ImageView>
5
+<TextView android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFFFFF" android:layout_marginLeft="15dip" android:textSize="20dip" android:text="@string/app_name" android:autoLink="web"></TextView>
6
+</LinearLayout>
7
+<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/about" android:gravity="center" android:id="@+id/tvAbout" android:layout_marginBottom="20dip" android:layout_marginTop="20dip"></TextView>
8
+</LinearLayout>

+ 28
- 0
res/layout/list.xml View File

@@ -0,0 +1,28 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<LinearLayout android:id="@+id/LinearLayout01" 
3
+	android:layout_width="fill_parent" 
4
+	android:layout_height="fill_parent" 
5
+	android:orientation="vertical"
6
+	xmlns:android="http://schemas.android.com/apk/res/android">
7
+	<LinearLayout android:id="@+id/LinearLayout02"
8
+  		android:layout_height="wrap_content" 
9
+  		android:gravity="center" 
10
+  		android:orientation="horizontal" 
11
+  		android:layout_gravity="center_horizontal" 
12
+  		android:layout_width="fill_parent" 
13
+  		android:background="@drawable/list_location">
14
+		<ImageView android:id="@+id/ImageView01" 
15
+			android:layout_gravity="center" 
16
+			android:background="@drawable/gps_fix1" 
17
+			android:scaleType="centerCrop" 
18
+			android:layout_width="30dip" 
19
+			android:layout_height="30dip"/>
20
+		<org.r3pek.pharmacies.widgets.ScrollTextView android:layout_width="fill_parent" 
21
+			android:layout_height="wrap_content" 
22
+			android:id="@+id/tvLocation"
23
+		    android:singleLine="true"/>
24
+	</LinearLayout>
25
+	<ListView android:layout_width="fill_parent" 
26
+		android:layout_height="wrap_content" 
27
+		android:id="@+id/list"/>
28
+</LinearLayout>

+ 15
- 0
res/layout/list_row.xml View File

@@ -0,0 +1,15 @@
1
+<TableLayout android:id="@+id/TableLayout01" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android">
2
+	<TableRow android:id="@+id/TableRow01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dip">
3
+		<ImageView android:layout_column="0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/ivStatus" android:layout_marginLeft="5dip" android:layout_gravity="center_vertical"></ImageView>
4
+		<TextView android:layout_column="1" android:text="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFFFFF" android:textSize="20dip" android:id="@+id/tvNome" android:layout_marginLeft="10dip" android:layout_gravity="center_vertical"></TextView>
5
+	</TableRow>
6
+	<TableRow android:id="@+id/TableRow02" android:layout_width="wrap_content" android:layout_height="wrap_content">
7
+		<TextView android:layout_column="1" android:text="@+id/TextView02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dip" android:id="@+id/tvMorada" android:layout_marginLeft="10dip"></TextView>
8
+	</TableRow>
9
+	<TableRow android:id="@+id/TableRow03" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="5dip">
10
+		<LinearLayout android:layout_column="1" android:id="@+id/LinearLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="5dip" android:layout_gravity="center_vertical">
11
+			<TextView android:text="@+id/TextView01" android:layout_width="wrap_content" android:id="@+id/tvDistancia" android:layout_marginLeft="10dip" android:layout_height="wrap_content" android:layout_gravity="center_vertical"></TextView>
12
+			<org.r3pek.pharmacies.widgets.Arrow android:id="@+id/ivDirection" android:layout_marginLeft="5dip" android:layout_height="20dip" android:layout_width="20dip"></org.r3pek.pharmacies.widgets.Arrow>
13
+		</LinearLayout>
14
+	</TableRow>
15
+</TableLayout>

+ 10
- 0
res/layout/map.xml View File

@@ -0,0 +1,10 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+
3
+<LinearLayout android:layout_width="fill_parent" 
4
+			android:layout_height="fill_parent" 
5
+			xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/LinearLayout01" android:orientation="vertical">
6
+			<com.google.android.maps.MapView android:id="@+id/MapView"
7
+                android:layout_width="fill_parent"
8
+                android:apiKey="0DR5WqW9XXYhbuY0iKmL3qQ6CIbplUTonfkmHjA" android:layout_height="wrap_content">
9
+            </com.google.android.maps.MapView>
10
+</LinearLayout>

+ 11
- 0
res/layout/mylocation_balloon.xml View File

@@ -0,0 +1,11 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+
3
+<LinearLayout android:id="@+id/LinearLayout01"
4
+	xmlns:android="http://schemas.android.com/apk/res/android"
5
+	android:layout_width="fill_parent"
6
+	android:layout_height="fill_parent"
7
+	android:orientation="vertical"
8
+	android:background="@drawable/dialog">
9
+	
10
+<TextView android:text="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tvLocation" android:layout_gravity="center" android:textColor="#000000"></TextView>
11
+</LinearLayout>

+ 76
- 0
res/layout/pharmacy_balloon.xml View File

@@ -0,0 +1,76 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+
3
+<LinearLayout android:id="@+id/LinearLayout01"
4
+	xmlns:android="http://schemas.android.com/apk/res/android"
5
+	android:layout_width="fill_parent"
6
+	android:layout_height="fill_parent"
7
+	android:minWidth="270dip"
8
+	android:orientation="vertical"
9
+	android:background="@drawable/dialog">
10
+	<LinearLayout android:id="@+id/TableLayout01"
11
+		android:layout_width="fill_parent" 
12
+		android:layout_height="wrap_content">
13
+			<ImageView android:layout_width="wrap_content" 
14
+				android:layout_height="wrap_content" 
15
+				android:id="@+id/ivStatus" 
16
+				android:layout_gravity="center"/>
17
+			<TextView android:textColor="#000000" 
18
+				android:id="@+id/tvBalloonName" 
19
+				android:layout_height="wrap_content" 
20
+				android:textStyle="bold" 
21
+				android:gravity="left|center_vertical" 
22
+				android:layout_width="fill_parent" 
23
+				android:layout_weight="1"
24
+				android:layout_marginLeft="5dip"/>
25
+			<TextView android:layout_width="wrap_content" 
26
+				android:layout_height="wrap_content" 
27
+				android:layout_gravity="center"
28
+				android:layout_marginLeft="10dip"
29
+				android:id="@+id/tvDistance" 
30
+				android:textColor="#000000" 
31
+				android:gravity="right"
32
+				android:textSize="12dip"/>
33
+			<org.r3pek.pharmacies.widgets.Compass android:id="@+id/compass" 
34
+				android:layout_height="15dip" 
35
+				android:layout_width="15dip"
36
+				android:layout_marginLeft="5dip"
37
+				android:gravity="right"
38
+				android:layout_gravity="center"/>
39
+	</LinearLayout>
40
+	<LinearLayout android:id="@+id/LinearLayout02" 
41
+		android:layout_height="wrap_content" 
42
+		android:orientation="horizontal" 
43
+		android:layout_marginTop="10dip" 
44
+		android:layout_width="fill_parent" 
45
+		android:gravity="center">
46
+		<Button android:layout_width="wrap_content" 
47
+			android:layout_height="wrap_content" 
48
+			android:id="@+id/btnBalloonDetalhes" 
49
+			android:background="@xml/dialog_button" 
50
+			android:drawableLeft="@drawable/icon_details" 
51
+			android:drawablePadding="5dip" 
52
+			android:text="@string/details" 
53
+			android:paddingLeft="5dip" 
54
+			android:paddingRight="5dip"/>
55
+		<Button android:layout_width="wrap_content" 
56
+			android:layout_height="wrap_content" 
57
+			android:id="@+id/btnBalloonTelef" 
58
+			android:layout_marginLeft="5dip" 
59
+			android:background="@xml/dialog_button" 
60
+			android:drawablePadding="5dip" 
61
+			android:drawableLeft="@drawable/icon_call" 
62
+			android:text="@string/dial" 
63
+			android:paddingRight="5dip" 
64
+			android:paddingLeft="5dip"/>
65
+		<Button android:layout_width="wrap_content" 
66
+			android:layout_height="wrap_content" 
67
+			android:id="@+id/btnBalloonNav" 
68
+			android:layout_marginLeft="5dip" 
69
+			android:background="@xml/dialog_button" 
70
+			android:drawableLeft="@drawable/icon_car" 
71
+			android:text="@string/navigate" 
72
+			android:paddingLeft="5dip" 
73
+			android:paddingRight="5dip" 
74
+			android:drawablePadding="5dip"/>
75
+	</LinearLayout>
76
+</LinearLayout>

+ 157
- 0
res/layout/pharmacyinfo.xml View File

@@ -0,0 +1,157 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<RelativeLayout android:id="@+id/LinearLayout02"
3
+			android:orientation="vertical"
4
+			android:layout_width="fill_parent" 
5
+			android:layout_height="fill_parent"
6
+			xmlns:myapp="http://schemas.android.com/apk/res/org.r3pek.pharmacies"
7
+			xmlns:android="http://schemas.android.com/apk/res/android">
8
+	<ScrollView android:id="@+id/ScrollView01" 
9
+				android:layout_width="fill_parent" 
10
+				android:layout_height="fill_parent"> 
11
+		<LinearLayout android:id="@+id/LinearLayout01" 
12
+					android:layout_height="wrap_content" 
13
+					android:orientation="vertical" 
14
+					android:layout_width="fill_parent">
15
+			<TextView android:text="@+id/TextView01" 
16
+					android:layout_height="wrap_content" 
17
+					android:layout_gravity="center" 
18
+					android:layout_width="fill_parent" 
19
+					android:layout_margin="10dip" 
20
+					android:gravity="center" 
21
+					android:layout_marginRight="10dip" 
22
+					android:id="@+id/tvName" 
23
+					android:textColor="#FFFFFF" 
24
+					android:textSize="22dip" 
25
+					android:scrollHorizontally="true"/>
26
+			<TableLayout android:id="@+id/TableLayout01" 
27
+						android:layout_width="wrap_content" 
28
+						android:layout_height="wrap_content"
29
+						android:stretchColumns="1" 
30
+						android:layout_marginLeft="10dip">
31
+				<TableRow android:id="@+id/TableRow07" 
32
+						android:layout_width="wrap_content" 
33
+						android:layout_height="wrap_content"
34
+						android:layout_marginTop="5dip">
35
+					<TextView android:id="@+id/TextView07" 
36
+							android:layout_width="wrap_content" 
37
+							android:layout_height="wrap_content" 
38
+							android:text="@string/address" 
39
+							android:textStyle="bold"/>
40
+					<TextView android:id="@+id/tvAddress" 
41
+							android:layout_width="wrap_content" 
42
+							android:layout_height="wrap_content" 
43
+							android:text=""
44
+							android:layout_marginLeft="10dip"/> 
45
+				</TableRow>
46
+				<TableRow android:id="@+id/TableRow06" 
47
+						android:layout_width="wrap_content" 
48
+						android:layout_height="wrap_content"
49
+						android:layout_marginTop="5dip">
50
+					<TextView android:id="@+id/TextView06" 
51
+							android:layout_width="wrap_content" 
52
+							android:layout_height="wrap_content" 
53
+							android:text="@string/parish" 
54
+							android:textStyle="bold"/>
55
+					<TextView android:id="@+id/tvParish" 
56
+							android:layout_width="wrap_content" 
57
+							android:layout_height="wrap_content" 
58
+							android:text=""
59
+							android:layout_marginLeft="10dip"/> 
60
+				</TableRow>
61
+				<TableRow android:id="@+id/TableRow01" 
62
+						android:layout_width="wrap_content" 
63
+						android:layout_height="wrap_content"
64
+						android:layout_marginTop="5dip">
65
+					<TextView android:id="@+id/TextView01" 
66
+							android:layout_width="wrap_content" 
67
+							android:layout_height="wrap_content" 
68
+							android:text="@string/distance" 
69
+							android:textStyle="bold"/>
70
+					<LinearLayout android:id="@+id/LinearLayout04" 
71
+							android:layout_width="wrap_content" 
72
+							android:layout_height="wrap_content" 
73
+							android:layout_marginLeft="10dip">
74
+						<TextView android:text="@+id/TextView02" 
75
+								android:layout_width="wrap_content" 
76
+								android:layout_height="wrap_content" 
77
+								android:id="@+id/tvDistance"/>
78
+						<org.r3pek.pharmacies.widgets.Arrow android:id="@+id/ivInfoDirection" 
79
+								android:layout_marginLeft="5dip" 
80
+								android:layout_height="20dip" 
81
+								android:layout_width="20dip"/>
82
+					</LinearLayout>
83
+				</TableRow>
84
+				<TableRow android:id="@+id/TableRow02" 
85
+						android:layout_width="wrap_content" 
86
+						android:layout_height="wrap_content"
87
+						android:layout_marginTop="5dip">
88
+					<TextView android:id="@+id/TextView02" 
89
+							android:layout_width="wrap_content" 
90
+							android:layout_height="wrap_content" 
91
+							android:text="@string/phone_number" 
92
+							android:textStyle="bold"/>
93
+					<TextView android:id="@+id/tvPhoneNumber" 
94
+							android:layout_width="wrap_content" 
95
+							android:layout_height="wrap_content" 
96
+							android:text=""
97
+							android:layout_marginLeft="10dip"/> 
98
+				</TableRow>
99
+				<TableRow android:id="@+id/TableRow03" 
100
+						android:layout_width="wrap_content" 
101
+						android:layout_height="wrap_content"
102
+						android:layout_marginTop="5dip">
103
+					<TextView android:id="@+id/TextView03" 
104
+							android:layout_width="wrap_content" 
105
+							android:layout_height="wrap_content" 
106
+							android:text="@string/at_service" 
107
+							android:textStyle="bold"/>
108
+					<TextView android:id="@+id/tvOnDuty" 
109
+							android:layout_width="wrap_content" 
110
+							android:layout_height="wrap_content" 
111
+							android:text=""
112
+							android:layout_marginLeft="10dip"/> 
113
+				</TableRow>
114
+				<TableRow android:id="@+id/TableRow04" 
115
+						android:layout_width="wrap_content" 
116
+						android:layout_height="wrap_content"
117
+						android:layout_marginTop="5dip">
118
+					<TextView android:id="@+id/TextView04" 
119
+							android:layout_width="wrap_content" 
120
+							android:layout_height="wrap_content" 
121
+							android:text="@string/latitude" 
122
+							android:textStyle="bold"/>
123
+					<TextView android:id="@+id/tvLatitude" 
124
+							android:layout_width="wrap_content" 
125
+							android:layout_height="wrap_content" 
126
+							android:text=""
127
+							android:layout_marginLeft="10dip"/> 
128
+				</TableRow>
129
+				<TableRow android:id="@+id/TableRow05" 
130
+						android:layout_width="wrap_content" 
131
+						android:layout_height="wrap_content"
132
+						android:layout_marginTop="5dip">
133
+					<TextView android:id="@+id/TextView05" 
134
+							android:layout_width="wrap_content" 
135
+							android:layout_height="wrap_content" 
136
+							android:text="@string/longitude" 
137
+							android:textStyle="bold"/>
138
+					<TextView android:id="@+id/tvLongitude" 
139
+							android:layout_width="wrap_content" 
140
+							android:layout_height="wrap_content" 
141
+							android:text=""
142
+							android:layout_marginLeft="10dip"/> 
143
+				</TableRow>
144
+			</TableLayout>
145
+		</LinearLayout>
146
+	</ScrollView>
147
+	<com.admob.android.ads.AdView
148
+		android:id="@+id/ad"
149
+		android:layout_width="fill_parent"
150
+		android:layout_height="wrap_content"
151
+		android:layout_alignParentBottom="true"
152
+		android:gravity="bottom"
153
+		myapp:backgroundColor="#000000"
154
+		myapp:primaryTextColor="#FFFFFF"
155
+		myapp:secondaryTextColor="#CCCCCC"
156
+	/>
157
+</RelativeLayout>

+ 42
- 0
res/values-en/strings.xml View File

@@ -0,0 +1,42 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<resources>
3
+	<string name="about">Fármacias was developed by Carlos Silva and uses Sapo's services to fetch the information about the pharmacies. If the application was usefull, and if you want to, make a donation at www.r3pek.org. It also uses some icons from Yusuke Kamiyamane (p.yusukekamiyamane.com). Thanks.</string>
4
+	<string name="app_name">Farmácias</string>
5
+	<string name="pref_gen_cat">General</string>
6
+	<string name="pref_gen_onservice">Only display on Service</string>
7
+	<string name="pref_gen_maxdist">Max Distance</string>
8
+	<string name="distance">Distance:</string>
9
+	<string name="phone_number">Phone Number:</string>
10
+	<string name="at_service">At Service:</string>
11
+	<string name="latitude">Latitude:</string>
12
+	<string name="longitude">Longitude:</string>
13
+	<string name="yes">Yes</string>
14
+	<string name="no">No</string>
15
+	<string name="parish">Parish:</string>
16
+	<string name="address">Address:</string>
17
+	<string name="location_acquired">Location acquired</string>
18
+	<string name="dial">Dial</string>
19
+	<string name="share">Share</string>
20
+	<string name="navigate">Navigate</string>
21
+	<string name="copy_to_clipboard">Copy to Clipboard</string>
22
+	<string name="copied_to_clipboard">Copied to Clipboard</string>
23
+	<string name="shared_pharmacy">Shared Pharmacy</string>
24
+	<string name="details">Details</string>
25
+	<string name="error_getting_pharmacies">Error while retreiving pharmacies</string>
26
+	<string name="menu_refresh">Refresh</string>
27
+	<string name="menu_settings">Settings</string>
28
+	<string name="menu_list">List</string>
29
+	<string name="menu_about">About</string>
30
+	<string name="no_localization_active">You don't have any localization system active. Want to activate now?</string>
31
+	<string name="menu_get_gps_pos">Get GPS position</string>
32
+	<string name="menu_set_my_location">Set my location</string>
33
+	<string name="tap_on_screen">Tap on the screen to select your location</string>
34
+	<string name="now_from_GPS">Now using GPS for location</string>
35
+	<string name="menu_my_location">Goto my location</string>
36
+	<string name="not_available">Street name not available</string>
37
+	<string name="not_pharmacies_returned">Didn\'t get any pharmacies, try to increase the distance</string>
38
+	<string name="na">Not available</string>
39
+	<string name="show_on_map">Show on Map</string>
40
+	<string name="go_back">Now go back to the map</string>
41
+	<string name="loading">Loading...</string>
42
+</resources>

+ 42
- 0
res/values-pt/strings.xml View File

@@ -0,0 +1,42 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<resources>
3
+	<string name="about">A aplicação Farmácias de Serviço foi desenvolvida por Carlos Silva e usa os serviços da Sapo para ir buscar as informações sobre as farmácias. Se a aplicação lhe foi útil, e se achar que deve, faça um donativo em www.r3pek.org. Também são usados alguns icons do Yusuke Kamiyamane (p.yusukekamiyamane.com). Obrigado.</string>
4
+	<string name="app_name">Farmácias</string>
5
+	<string name="pref_gen_cat">Beral</string>
6
+	<string name="pref_gen_onservice">Só de serviço</string>
7
+	<string name="pref_gen_maxdist">Distância Máxima</string>
8
+	<string name="distance">Distância:</string>
9
+	<string name="phone_number">Telefone:</string>
10
+	<string name="at_service">De serviço:</string>
11
+	<string name="latitude">Latitude:</string>
12
+	<string name="longitude">Longitude:</string>
13
+	<string name="yes">Sim</string>
14
+	<string name="no">Não</string>
15
+	<string name="parish">Freguesia:</string>
16
+	<string name="address">Morada:</string>
17
+	<string name="location_acquired">Obtida localização</string>
18
+	<string name="dial">Telefonar</string>
19
+	<string name="share">Partilhar</string>
20
+	<string name="navigate">Navegar</string>
21
+	<string name="copy_to_clipboard">Copiar para o Clipboard</string>
22
+	<string name="copied_to_clipboard">Copiado para o Clipboard</string>
23
+	<string name="shared_pharmacy">Farmácia Partilhada</string>
24
+	<string name="details">Detalhes</string>
25
+	<string name="error_getting_pharmacies">Erro ao receber as Farmácias</string>
26
+	<string name="menu_refresh">Actualizar</string>
27
+	<string name="menu_settings">Configurações</string>
28
+	<string name="menu_list">Lista</string>
29
+	<string name="menu_about">Sobre</string>
30
+	<string name="no_localization_active">Não tem nenhum sistema de localização activo. Deseja activar?</string>
31
+	<string name="menu_get_gps_pos">Obter via GPS</string>
32
+	<string name="menu_set_my_location">Definir localização</string>
33
+	<string name="tap_on_screen">Toque no ecrã para definir a sua localização</string>
34
+	<string name="now_from_GPS">Agora a usar o GPS para obter a localização</string>
35
+	<string name="menu_my_location">Ir para localização</string>
36
+	<string name="not_available">Nome da rua não disponível</string>
37
+	<string name="not_pharmacies_returned">Nenhuma farmácia obtida, tenta aumentar a distância máxima</string>
38
+	<string name="na">Não disponível</string>
39
+	<string name="show_on_map">Mostrar no Mapa</string>
40
+	<string name="go_back">Volte para o mapa</string>
41
+	<string name="loading">À procura...</string>
42
+</resources>

+ 10
- 0
res/values/attrs.xml View File

@@ -0,0 +1,10 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<resources>
3
+	<declare-styleable name="com.admob.android.ads.AdView">
4
+		<attr name="backgroundColor" format="color" />
5
+		<attr name="primaryTextColor" format="color" />
6
+		<attr name="secondaryTextColor" format="color" />
7
+		<attr name="keywords" format="string" />
8
+		<attr name="refreshInterval" format="integer" />
9
+	</declare-styleable>
10
+</resources>

+ 6
- 0
res/xml/dialog_button.xml View File

@@ -0,0 +1,6 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
3
+     <item android:state_pressed="true"
4
+           android:drawable="@drawable/button_pressed" /> <!-- pressed -->
5
+     <item android:drawable="@drawable/button_normal" /> <!-- default -->
6
+ </selector>

+ 15
- 0
res/xml/preferences.xml View File

@@ -0,0 +1,15 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<PreferenceScreen
3
+	xmlns:android="http://schemas.android.com/apk/res/android" 
4
+	android:key="preferences">
5
+	<PreferenceCategory android:key="general" 
6
+		android:title="@string/pref_gen_cat">
7
+		<CheckBoxPreference android:title="@string/pref_gen_onservice" 
8
+			android:key="pref_gen_just_onservice"/>
9
+		<org.r3pek.pharmacies.widgets.SeekBarPreference android:key="pref_gen_maxdist" 
10
+			android:title="@string/pref_gen_maxdist" 
11
+			android:max="10"
12
+			android:defaultValue="2" 
13
+			android:text=" Km"/>
14
+	</PreferenceCategory>
15
+</PreferenceScreen>

+ 23
- 0
src/org/r3pek/pharmacies/ConfigValues.java View File

@@ -0,0 +1,23 @@
1
+package org.r3pek.pharmacies;
2
+
3
+import android.content.Context;
4
+import android.content.SharedPreferences;
5
+import android.preference.PreferenceManager;
6
+
7
+public class ConfigValues {
8
+	private static SharedPreferences settings;
9
+
10
+	public ConfigValues(Context ctx) {
11
+		settings = PreferenceManager.getDefaultSharedPreferences(ctx);
12
+	}
13
+
14
+	public boolean isOnlyService() {
15
+		return settings.getBoolean("pref_gen_just_onservice", false);
16
+	}
17
+
18
+	public int getRadius() {
19
+		int dist = settings.getInt("pref_gen_maxdist", 2000); 
20
+		return dist == 2000 ? dist : dist * 1000;
21
+	}
22
+
23
+}

+ 54
- 0
src/org/r3pek/pharmacies/GetPositionOverlay.java View File

@@ -0,0 +1,54 @@
1
+package org.r3pek.pharmacies;
2
+
3
+import org.r3pek.pharmacies.utils.GlobalVars;
4
+
5
+import android.graphics.drawable.Drawable;
6
+import android.location.Location;
7
+import android.location.LocationManager;
8
+import android.os.Handler;
9
+
10
+import com.google.android.maps.GeoPoint;
11
+import com.google.android.maps.ItemizedOverlay;
12
+import com.google.android.maps.MapView;
13
+import com.google.android.maps.OverlayItem;
14
+
15
+public class GetPositionOverlay extends ItemizedOverlay<OverlayItem> {
16
+	private PharmaciesOverlay pharmacies; 
17
+	private MyPositionOverlay myLocation;
18
+	private Handler onSelectionHandler;
19
+
20
+	public GetPositionOverlay(Drawable defaultMarker, PharmaciesOverlay pharmacies, MyPositionOverlay myLocation, Handler onSelectionHandler) {
21
+		super(defaultMarker);
22
+		this.pharmacies = pharmacies;
23
+		this.myLocation = myLocation;
24
+		this.onSelectionHandler = onSelectionHandler;
25
+		populate();
26
+	}
27
+
28
+	@Override
29
+	protected OverlayItem createItem(int i) {
30
+		return null;
31
+	}
32
+
33
+	@Override
34
+	public int size() {
35
+		return 0;
36
+	}
37
+
38
+	@Override
39
+	public boolean onTap(GeoPoint p, MapView map) {
40
+		Location l = new Location(LocationManager.GPS_PROVIDER);
41
+		l.setLatitude(p.getLatitudeE6()/1000000.0);
42
+		l.setLongitude(p.getLongitudeE6()/1000000.0);
43
+		l.setAccuracy(0.0f);
44
+		GlobalVars.getPharmacies().clear();
45
+		pharmacies.refresh();
46
+		onSelectionHandler.sendEmptyMessage(0);
47
+		GlobalVars.positioner.setFixedLocation(l);
48
+		map.getOverlays().clear();
49
+		map.getOverlays().add(pharmacies);
50
+		map.getOverlays().add(myLocation);
51
+		map.postInvalidate();
52
+		return super.onTap(p, map);
53
+	}
54
+}

+ 161
- 0
src/org/r3pek/pharmacies/MyPositionOverlay.java View File

@@ -0,0 +1,161 @@
1
+package org.r3pek.pharmacies;
2
+
3
+import java.util.Timer;
4
+import java.util.TimerTask;
5
+
6
+import org.r3pek.pharmacies.utils.GeoUtils;
7
+import org.r3pek.pharmacies.utils.GlobalVars;
8
+import org.r3pek.pharmacies.utils.OnPositionChangeListener;
9
+
10
+import android.app.Activity;
11
+import android.content.Context;
12
+import android.graphics.Canvas;
13
+import android.graphics.Paint;
14
+import android.graphics.Point;
15
+import android.graphics.Paint.Style;
16
+import android.graphics.drawable.Drawable;
17
+import android.graphics.drawable.LevelListDrawable;
18
+import android.os.Handler;
19
+import android.os.Message;
20
+import android.os.Handler.Callback;
21
+import android.view.LayoutInflater;
22
+import android.view.View;
23
+import android.view.ViewGroup;
24
+import android.widget.LinearLayout;
25
+import android.widget.TextView;
26
+
27
+import com.google.android.maps.GeoPoint;
28
+import com.google.android.maps.MapView;
29
+import com.google.android.maps.Overlay;
30
+import com.google.android.maps.Projection;
31
+import com.google.android.maps.MapView.LayoutParams;
32
+
33
+public class MyPositionOverlay extends Overlay implements OnPositionChangeListener {
34
+	private static final float dotScale = 0.6f;
35
+	private MapView map;
36
+	private Runnable runOnFirstFix;
37
+	private boolean isFirstFix;
38
+	private LevelListDrawable netLocationImage;
39
+	private LevelListDrawable gpsLocationImage;
40
+	private Timer updateDotTask;
41
+	private Context context;
42
+	private View shownView;
43
+	private Activity mapActivity;
44
+
45
+	public MyPositionOverlay(Context ctx, MapView mapView, Activity mapActivity) {
46
+		super();
47
+		map = mapView;
48
+		this.mapActivity = mapActivity; 
49
+		GlobalVars.positioner.registerNotification(this);
50
+		isFirstFix = true;
51
+		context = ctx;
52
+       	netLocationImage = (LevelListDrawable) ctx.getResources().getDrawable(R.drawable.network_fix);
53
+       	gpsLocationImage = (LevelListDrawable) ctx.getResources().getDrawable(R.drawable.gps_fix);
54
+       	
55
+       	updateDotTask = new Timer();
56
+       	TimerTask tt = new TimerTask() {
57
+			@Override
58
+			public void run() {
59
+				if (GlobalVars.positioner.isGPSFix()) return;
60
+				int current = netLocationImage.getLevel();
61
+				current = (current + 1) % 4;
62
+				netLocationImage.setLevel(current);
63
+				map.postInvalidate();
64
+			}
65
+		};
66
+		updateDotTask.scheduleAtFixedRate(tt, 100, 500);
67
+	}
68
+	
69
+	@Override
70
+	public void draw(Canvas canvas, MapView mapView, boolean shadow) {
71
+		if (shadow || isFirstFix) return;
72
+        if (GlobalVars.positioner.getLastGeoPoint() == null) return;
73
+
74
+        Projection projection = mapView.getProjection();
75
+        Point point = new Point();
76
+        projection.toPixels(GlobalVars.positioner.getLastGeoPoint(), point);
77
+
78
+        // Draw the accuracy circle
79
+        float radius = projection.metersToEquatorPixels(GlobalVars.positioner.getLastAccuracy());
80
+        canvas.save();
81
+        Paint circlePaint = new Paint();
82
+        circlePaint.setStyle(Style.FILL);
83
+        circlePaint.setARGB(10, 0, 0, 255);
84
+        canvas.drawCircle(point.x, point.y, radius, circlePaint);
85
+        circlePaint.setARGB(200, 0, 0, 255);
86
+        circlePaint.setStyle(Style.STROKE);
87
+        canvas.drawCircle(point.x, point.y, radius, circlePaint);
88
+        canvas.restore();
89
+
90
+        // Draw in the right spot
91
+        Drawable d = GlobalVars.positioner.isGPSFix() ? gpsLocationImage.getCurrent() : netLocationImage.getCurrent();
92
+        int scaledImageWidth =  (int)(d.getIntrinsicWidth() * dotScale);
93
+        int scaledImageHeight =  (int)(d.getIntrinsicHeight() * dotScale);
94
+        float scaledImageCenterX = scaledImageWidth / 2;
95
+        float scaledImageCenterY = scaledImageHeight / 2;
96
+
97
+        canvas.save();
98
+        canvas.translate(-(scaledImageCenterX - point.x), -(scaledImageCenterY - point.y));
99
+        d.setBounds(0, 0, scaledImageWidth, scaledImageHeight);
100
+        d.getCurrent().draw(canvas);
101
+        canvas.restore();
102
+
103
+        super.draw(canvas, mapView, shadow);
104
+	}
105
+	
106
+	@Override
107
+	public void onLocationChange(GeoPoint currentPos, float accuracy) {
108
+		if (isFirstFix) {
109
+			isFirstFix = false;
110
+			runOnFirstFix.run();
111
+		}
112
+		map.postInvalidate();
113
+	}
114
+	
115
+	public void disableMyLocation() {
116
+		GlobalVars.positioner.unregisterNotification(this);
117
+	}
118
+	
119
+	public void enableMyLocation() {
120
+		GlobalVars.positioner.registerNotification(this);
121
+	}
122
+	
123
+	public void runOnFirstFix(Runnable r) {
124
+		runOnFirstFix = r;
125
+	}
126
+	
127
+	@Override
128
+	public boolean onTap(GeoPoint p, MapView map) {
129
+		Point pointTap = map.getProjection().toPixels(p, null);
130
+		Point pointMap = map.getProjection().toPixels(GlobalVars.positioner.getLastGeoPoint(), null);
131
+		if (Math.abs(pointTap.x - pointMap.x) <= 20 && Math.abs(pointMap.y - pointTap.y) <= 20 && shownView == null) {
132
+			LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
133
+			LinearLayout ll = (LinearLayout)inflater.inflate(R.layout.mylocation_balloon, null);
134
+			LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, GlobalVars.positioner.getLastGeoPoint(), 0, -35, LayoutParams.MODE_MAP | LayoutParams.CENTER);
135
+			
136
+			final TextView tvLocation = (TextView)ll.findViewById(R.id.tvLocation);
137
+			tvLocation.setText(context.getString(R.string.loading));
138
+			map.getController().animateTo(GlobalVars.positioner.getLastGeoPoint());
139
+			map.addView(ll, lp);
140
+			shownView = ll;
141
+			GeoUtils.getLocationName(context, new Handler(new Callback() {
142
+				@Override
143
+				public boolean handleMessage(Message msg) {
144
+					final String location = msg.getData().getString("location");
145
+						mapActivity.runOnUiThread(new Runnable() {
146
+							@Override
147
+							public void run() {
148
+								tvLocation.setText(location);
149
+							}
150
+						});
151
+						return true;
152
+					}
153
+				}));
154
+		} else if (shownView != null) {
155
+			map.removeView(shownView);
156
+			shownView = null;
157
+		}
158
+        return super.onTap(p, map);
159
+	}
160
+
161
+}

+ 18
- 0
src/org/r3pek/pharmacies/MyPreferences.java View File

@@ -0,0 +1,18 @@
1
+package org.r3pek.pharmacies;
2
+
3
+import org.r3pek.pharmacies.widgets.SeekBarPreference;
4
+
5
+import android.os.Bundle;
6
+import android.preference.PreferenceActivity;
7
+
8
+public class MyPreferences extends PreferenceActivity {
9
+
10
+    public void onCreate(Bundle savedInstanceState) {
11
+		super.onCreate(savedInstanceState);
12
+
13
+		addPreferencesFromResource(R.xml.preferences);
14
+		
15
+		SeekBarPreference sbp = (SeekBarPreference) findPreference("pref_gen_maxdist");
16
+		sbp.setMin(1);
17
+    }    
18
+}

+ 166
- 0
src/org/r3pek/pharmacies/PharmaciesOverlay.java View File

@@ -0,0 +1,166 @@
1
+package org.r3pek.pharmacies;
2
+
3
+import java.util.LinkedList;
4
+
5
+import org.r3pek.pharmacies.utils.GeoUtils;
6
+import org.r3pek.pharmacies.utils.GlobalVars;
7
+import org.r3pek.pharmacies.widgets.Compass;
8
+import org.r3pek.pharmacies.widgets.ImageRotater;
9
+
10
+import android.content.ActivityNotFoundException;
11
+import android.content.Context;
12
+import android.content.Intent;
13
+import android.graphics.drawable.Drawable;
14
+import android.hardware.Sensor;
15
+import android.hardware.SensorManager;
16
+import android.net.Uri;
17
+import android.view.LayoutInflater;
18
+import android.view.View;
19
+import android.view.ViewGroup;
20
+import android.view.View.OnClickListener;
21
+import android.widget.Button;
22
+import android.widget.ImageView;
23
+import android.widget.LinearLayout;
24
+import android.widget.TextView;
25
+
26
+import com.google.android.maps.GeoPoint;
27
+import com.google.android.maps.ItemizedOverlay;
28
+import com.google.android.maps.MapView;
29
+import com.google.android.maps.OverlayItem;
30
+import com.google.android.maps.MapView.LayoutParams;
31
+
32
+public class PharmaciesOverlay extends ItemizedOverlay<OverlayItem> {
33
+	private Context ctx;
34
+	private MapView mapView;
35
+	private View shownView;
36
+	private SensorManager sm; 
37
+	private ImageRotater cRotator;
38
+	private Compass compass;
39
+	private LinkedList<Pharmacy> pharmacies;
40
+	
41
+	public PharmaciesOverlay(Drawable defaultMarker, Context ctx, MapView mapView) {
42
+		super(boundCenterBottom(defaultMarker));
43
+		this.ctx = ctx;
44
+		this.mapView = mapView;
45
+		shownView = null;
46
+		populate();
47
+        sm = (SensorManager)ctx.getSystemService(Context.SENSOR_SERVICE);
48
+        cRotator = new ImageRotater();
49
+        pharmacies = new LinkedList<Pharmacy>();
50
+	}
51
+
52
+	@Override
53
+	protected synchronized OverlayItem createItem(int i) {
54
+		Pharmacy p = pharmacies.get(i);
55
+		OverlayItem result = new OverlayItem(p.getGeoPoint(), p.getName(), "");
56
+		if (p.isAtService()) 
57
+			result.setMarker(boundCenterBottom(ctx.getResources().getDrawable(R.drawable.pin_on)));
58
+		return result;
59
+	}
60
+
61
+	@Override
62
+	public synchronized int size() {
63
+		if (pharmacies == null) return 0;
64
+		return pharmacies.size();
65
+	}
66
+	
67
+	@Override
68
+	protected boolean onTap(final int i) {
69
+		if (mapView.getChildCount() > 0) return true;
70
+		LayoutInflater inflater = (LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
71
+		LinearLayout ll = (LinearLayout)inflater.inflate(R.layout.pharmacy_balloon, null);
72
+		
73
+		final Pharmacy pharm = GlobalVars.getPharmacies().get(i);
74
+		LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, pharm.getGeoPoint(), 0, -70, LayoutParams.MODE_MAP | LayoutParams.CENTER);
75
+
76
+		TextView tvName = (TextView)ll.findViewById(R.id.tvBalloonName);
77
+		TextView tvDistance = (TextView)ll.findViewById(R.id.tvDistance);
78
+		ImageView ivStatus = (ImageView)ll.findViewById(R.id.ivStatus);
79
+		Button btnDetalhes = (Button)ll.findViewById(R.id.btnBalloonDetalhes);
80
+		Button btnTelef = (Button)ll.findViewById(R.id.btnBalloonTelef);
81
+		Button btnNav = (Button)ll.findViewById(R.id.btnBalloonNav);
82
+		compass = (Compass)ll.findViewById(R.id.compass);
83
+		
84
+		btnTelef.setEnabled(!pharm.getPhoneNumber().equals(""));
85
+        compass.setBearing(GeoUtils.bearing(GlobalVars.positioner.getLastGeoPoint(), pharm.getGeoPoint()));
86
+        compass.setOrientation(cRotator.getLastOrientation());
87
+        sm.registerListener(cRotator, sm.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
88
+		cRotator.addImage(compass);
89
+		tvName.setText(pharm.getName());
90
+		tvDistance.setText(pharm.getDistance().substring(0, pharm.getDistance().indexOf(".")) + "m");
91
+		ivStatus.setBackgroundResource(pharm.isAtService() ? R.drawable.status_on : R.drawable.status_off);
92
+		btnDetalhes.setOnClickListener(new OnClickListener() {
93
+			@Override
94
+			public void onClick(View v) {
95
+				Intent pharmInfo = new Intent(ctx, PharmacyInfo.class);
96
+				pharmInfo.putExtra("org.r3pek.pharmacies.Pharmacy", pharm);
97
+				pharmInfo.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
98
+				ctx.startActivity(pharmInfo);
99
+			}
100
+		});
101
+		btnTelef.setOnClickListener(new OnClickListener() {
102
+			@Override
103
+			public void onClick(View v) {
104
+				Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + pharm.getPhoneNumber()));
105
+				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
106
+				ctx.startActivity(intent);
107
+			}
108
+		});
109
+		btnNav.setOnClickListener(new OnClickListener() {
110
+			@Override
111
+			public void onClick(View v) {
112
+		        StringBuilder url = new StringBuilder(); 
113
+		        url.append("http://maps.google.com/maps?f=d&hl=en"); 
114
+		        url.append("&saddr=");
115
+		        url.append( Double.toString((double)GlobalVars.positioner.getLastGeoPoint().getLatitudeE6()/1.0E6 )); 
116
+		        url.append(","); 
117
+		        url.append( Double.toString((double)GlobalVars.positioner.getLastGeoPoint().getLongitudeE6()/1.0E6 )); 
118
+		        url.append("&daddr=");
119
+		        url.append( Double.toString((double)pharm.getGeoPoint().getLatitudeE6()/1.0E6 )); 
120
+		        url.append(","); 
121
+		        url.append( Double.toString((double)pharm.getGeoPoint().getLongitudeE6()/1.0E6 ));   
122
+		        url.append("&dirflg=d&nav=1"); 
123
+				Intent intent = new Intent(Intent.ACTION_VIEW);
124
+				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
125
+				intent.setData(Uri.parse(url.toString()));
126
+				intent.addFlags(0x10800000);
127
+				intent.setClassName("com.google.android.apps.m4ps", "com.google.android.maps.driveabout.app.NavigationActivity");
128
+				
129
+				try {
130
+					ctx.startActivity(intent); 
131
+				} catch (ActivityNotFoundException e) {
132
+					intent.setClassName("com.google.android.apps.maps", "com.google.android.maps.driveabout.app.NavigationActivity");
133
+					try {
134
+						ctx.startActivity(intent);
135
+					} catch (ActivityNotFoundException e2) { }
136
+				}
137
+			}
138
+		});
139
+
140
+		shownView = ll;
141
+		mapView.addView(ll, lp);
142
+		mapView.getController().animateTo(pharm.getGeoPoint());
143
+
144
+		return super.onTap(i);
145
+	}
146
+	
147
+	public void removeBallon() {
148
+		cRotator.delImage(compass);
149
+		sm.unregisterListener(cRotator);
150
+		mapView.removeView(shownView);
151
+	}
152
+	
153
+	@Override
154
+	public boolean onTap(GeoPoint p, MapView map) {
155
+		removeBallon();
156
+		return super.onTap(p, map);
157
+	}
158
+	
159
+	public synchronized void refresh() {
160
+		pharmacies.clear();
161
+		for (Pharmacy p : GlobalVars.getPharmacies())
162
+			pharmacies.add(p);
163
+		populate();
164
+	}
165
+	
166
+}

+ 91
- 0
src/org/r3pek/pharmacies/Pharmacy.java View File

@@ -0,0 +1,91 @@
1
+package org.r3pek.pharmacies;
2
+
3
+import java.io.Serializable;
4
+
5
+import com.google.android.maps.GeoPoint;
6
+
7
+
8
+public class Pharmacy implements Serializable {
9
+	private static final long serialVersionUID = 1L;
10
+	
11
+	private String name;
12
+	private String address;
13
+	private String phoneNumber;
14
+	private String latitude;
15
+	private String longitude;
16
+	private String distance;
17
+	private Boolean atService;
18
+	private String parish;
19
+	
20
+	public Pharmacy() {
21
+	}
22
+	
23
+	public String getName() {
24
+		return name == null ? "" : name;
25
+	}
26
+	
27
+	public void setName(String name) {
28
+		this.name = name;
29
+	}
30
+	
31
+	public String getAddress() {
32
+		return address == null ? "" : address;
33
+	}
34
+	
35
+	public void setAddress(String address) {
36
+		this.address = address;
37
+	}
38
+	
39
+	public String getPhoneNumber() {
40
+		return phoneNumber == null ? "" : phoneNumber;
41
+	}
42
+	
43
+	public void setPhoneNumber(String phoneNumber) {
44
+		this.phoneNumber = phoneNumber;
45
+	}
46
+	
47
+	public String getLatitude() {
48
+		return latitude == null ? "" : latitude;
49
+	}
50
+	
51
+	public void setLatitude(String latitude) {
52
+		this.latitude = latitude;
53
+	}
54
+	
55
+	public String getLongitude() {
56
+		return longitude == null ? "" : longitude;
57
+	}
58
+	
59
+	public void setLongitude(String longitude) {
60
+		this.longitude = longitude;
61
+	}
62
+	
63
+	public String getDistance() {
64
+		return distance == null ? "" : distance;
65
+	}
66
+
67
+	public void setDistance(String distance) {
68
+		this.distance = distance;
69
+	}
70
+
71
+	public boolean isAtService() {
72
+		return atService;
73
+	}
74
+	
75
+	public void setAtService(boolean atService) {
76
+		this.atService = atService;
77
+	}
78
+
79
+	public String getParish() {
80
+		return parish == null ? "" : parish;
81
+	}
82
+
83
+	public void setParish(String parish) {
84
+		this.parish = parish;
85
+	}
86
+	
87
+	public GeoPoint getGeoPoint() {
88
+		return new GeoPoint((int)(Double.parseDouble(latitude) * 1E6), (int)(Double.parseDouble(longitude) * 1E6));
89
+	}
90
+
91
+}

+ 169
- 0
src/org/r3pek/pharmacies/PharmacyInfo.java View File

@@ -0,0 +1,169 @@
1
+package org.r3pek.pharmacies;
2
+
3
+import org.r3pek.pharmacies.utils.GeoUtils;
4
+import org.r3pek.pharmacies.utils.GlobalVars;
5
+import org.r3pek.pharmacies.widgets.Arrow;
6
+import org.r3pek.pharmacies.widgets.ImageRotater;
7
+
8
+import android.app.Activity;
9
+import android.content.Context;
10
+import android.content.Intent;
11
+import android.hardware.Sensor;
12
+import android.hardware.SensorManager;
13
+import android.location.Location;
14
+import android.net.Uri;
15
+import android.os.Bundle;
16
+import android.text.ClipboardManager;
17
+import android.view.Menu;
18
+import android.view.MenuItem;
19
+import android.widget.TextView;
20
+import android.widget.Toast;
21
+
22
+public class PharmacyInfo extends Activity {
23
+	private final static int MENU_DIAL = 0;
24
+	private final static int MENU_SHARE = 1;
25
+	private final static int MENU_NAVIGATE = 2;
26
+	private final static int MENU_COPY = 3;
27
+	private final static int MENU_SHOWONMAP = 4;
28
+	
29
+	private SensorManager sm;
30
+	private Pharmacy p;
31
+	private ImageRotater arrowChangerSensor;
32
+	private int pharmacyIndex;
33
+	
34
+	public void onCreate(Bundle savedInstanceState) {
35
+        super.onCreate(savedInstanceState);
36
+        setContentView(R.layout.pharmacyinfo);
37
+        
38
+        p = (Pharmacy)getIntent().getSerializableExtra("org.r3pek.pharmacies.Pharmacy");
39
+        pharmacyIndex = getIntent().getIntExtra("org.r3pek.pharmacies.PharmacyIndex", -1);
40
+        TextView tvName = (TextView)findViewById(R.id.tvName);
41
+        TextView tvAddress = (TextView)findViewById(R.id.tvAddress);
42
+        TextView tvParish = (TextView)findViewById(R.id.tvParish);
43
+        TextView tvPhoneNumber = (TextView)findViewById(R.id.tvPhoneNumber);
44
+        TextView tvLatitude = (TextView)findViewById(R.id.tvLatitude);
45
+        TextView tvLongitude = (TextView)findViewById(R.id.tvLongitude);
46
+        TextView tvDist = (TextView)findViewById(R.id.tvDistance);
47
+        Arrow arrow = (Arrow)findViewById(R.id.ivInfoDirection);
48
+        TextView tvService = (TextView)findViewById(R.id.tvOnDuty);
49
+        
50
+        sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
51
+        arrowChangerSensor = new ImageRotater();
52
+        arrow.setBearing(GeoUtils.bearing(GlobalVars.positioner.getLastGeoPoint(), p.getGeoPoint()));
53
+        arrow.setOrientation(arrowChangerSensor.getLastOrientation());
54
+        
55
+        tvName.setText(p.getName());
56
+        tvAddress.setText(p.getAddress());
57
+        tvParish.setText(p.getParish());
58
+        tvPhoneNumber.setText(p.getPhoneNumber().equals("") ? getString(R.string.na) : p.getPhoneNumber());
59
+        tvLatitude.setText(p.getLatitude());
60
+        tvLongitude.setText(p.getLongitude());
61
+        tvDist.setText(p.getDistance().substring(0, p.getDistance().indexOf(".")) + "m");
62
+        tvService.setText(p.isAtService() ? getString(R.string.yes) : getString(R.string.no));
63
+	}
64
+	
65
+	@Override
66
+	public void onResume() {
67
+    	sm.registerListener(arrowChangerSensor, sm.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
68
+		arrowChangerSensor.addImage((Arrow)findViewById(R.id.ivInfoDirection));
69
+    	super.onResume();
70
+	}
71
+	
72
+	@Override
73
+	public void onPause() {
74
+		arrowChangerSensor.delImage((Arrow)findViewById(R.id.ivInfoDirection));
75
+    	sm.unregisterListener(arrowChangerSensor);
76
+    	super.onPause();
77
+	}
78
+	
79
+	@Override
80
+    public boolean onCreateOptionsMenu(Menu menu) {
81
+        menu.add(0, MENU_DIAL, 0, getString(R.string.dial)).setIcon(android.R.drawable.ic_menu_call);
82
+        menu.add(0, MENU_SHARE, 1, getString(R.string.share)).setIcon(android.R.drawable.ic_menu_share);
83
+        menu.add(0, MENU_NAVIGATE, 2, getString(R.string.navigate)).setIcon(android.R.drawable.ic_menu_directions);
84
+        menu.add(0, MENU_COPY, 3, getString(R.string.copy_to_clipboard)).setIcon(R.drawable.copy);
85
+        menu.add(0, MENU_SHOWONMAP, 4, getString(R.string.show_on_map)).setIcon(android.R.drawable.ic_menu_mapmode);
86
+    	return true;
87
+    }
88
+	
89
+	@Override
90
+	public boolean onPrepareOptionsMenu(Menu menu) {
91
+		menu.findItem(MENU_DIAL).setEnabled(!p.getPhoneNumber().equals(""));
92
+		menu.findItem(MENU_SHOWONMAP).setEnabled(pharmacyIndex != -1);
93
+		
94
+		return true;
95
+	}
96
+	
97
+	@Override
98
+    public boolean onOptionsItemSelected(MenuItem item) {
99
+        switch (item.getItemId()) {
100
+	        case MENU_DIAL:
101
+	        	makeCall();
102
+	        	break;
103
+	        case MENU_SHARE:
104
+	        	share();
105
+	        	break;
106
+	        case MENU_NAVIGATE:
107
+	        	openNavigation();
108
+	        	break;
109
+	        case MENU_COPY:
110
+	        	copyAddrToClipboard();
111
+	        	break;
112
+	        case MENU_SHOWONMAP:
113
+	        	showOnMap();
114
+	        	break;
115
+        }
116
+        return true;
117
+    }
118
+	
119
+	private void showOnMap() {
120
+		GlobalVars.pharmaciesOverlay.onTap(pharmacyIndex);
121
+		Toast.makeText(getApplicationContext(), R.string.go_back, Toast.LENGTH_SHORT).show();
122
+	}
123
+    
124
+    private void share() {
125
+    	Intent i = new Intent(Intent.ACTION_SEND);
126
+    	i.setType("text/plain");
127
+    	i.putExtra(Intent.EXTRA_TEXT, p.getName() + '\n' +
128
+    			getString(R.string.address) + " " + p.getAddress() + '\n' +
129
+    			getString(R.string.distance) + " " + p.getDistance().substring(0, p.getDistance().indexOf(".")) + "m" + '\n' +
130
+    			getString(R.string.phone_number) + " " + (p.getPhoneNumber().equals("") ? getString(R.string.na) : p.getPhoneNumber()) + '\n' +
131
+    			getString(R.string.at_service) + " " + (p.isAtService() ? getString(R.string.yes) : getString(R.string.no)));
132
+    	startActivity(i);
133
+    }
134
+    
135
+    private void copyAddrToClipboard() {
136
+    	ClipboardManager cm = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
137
+    	cm.setText(p.getAddress());
138
+    	Toast.makeText(getApplicationContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show();
139
+    }
140
+    
141
+    private void makeCall() {
142
+		Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + p.getPhoneNumber()));
143
+		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
144
+		startActivity(intent);
145
+	}
146
+	
147
+	private void openNavigation() {
148
+        double lat = Double.parseDouble(p.getLatitude());
149
+        double lng = Double.parseDouble(p.getLongitude());
150
+        Location loc = GlobalVars.positioner.getLastLocation();
151
+        
152
+        StringBuilder url = new StringBuilder(); 
153
+        url.append("http://maps.google.com/maps?f=d&hl=en"); 
154
+        url.append("&saddr=");
155
+        url.append( Double.toString(loc.getLatitude())); 
156
+        url.append(","); 
157
+        url.append( Double.toString(loc.getLongitude())); 
158
+        url.append("&daddr=");
159
+        url.append( Double.toString(lat)); 
160
+        url.append(","); 
161
+        url.append( Double.toString(lng));   
162
+        url.append("&ie=UTF8&0&om=0"); 
163
+		Intent intent = new Intent(Intent.ACTION_VIEW);
164
+		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
165
+		intent.setData(Uri.parse(url.toString()));
166
+        startActivity(intent);
167
+	}
168
+
169
+}

+ 148
- 0
src/org/r3pek/pharmacies/PharmacyList.java View File

@@ -0,0 +1,148 @@
1
+package org.r3pek.pharmacies;
2
+
3
+import java.text.DecimalFormat;
4
+import java.util.ArrayList;
5
+import java.util.HashMap;
6
+import java.util.LinkedList;
7
+
8
+import org.r3pek.pharmacies.utils.GeoUtils;
9
+import org.r3pek.pharmacies.utils.GlobalVars;
10
+import org.r3pek.pharmacies.widgets.ImageRotater;
11
+import org.r3pek.pharmacies.widgets.ScrollTextView;
12
+
13
+import android.app.Activity;
14
+import android.content.Context;
15
+import android.content.Intent;
16
+import android.hardware.Sensor;
17
+import android.hardware.SensorManager;
18
+import android.os.Bundle;
19
+import android.os.Handler;
20
+import android.os.Message;
21
+import android.os.Handler.Callback;
22
+import android.view.View;
23
+import android.view.animation.AccelerateInterpolator;
24
+import android.view.animation.Animation;
25
+import android.view.animation.TranslateAnimation;
26
+import android.view.animation.Animation.AnimationListener;
27
+import android.widget.AdapterView;
28
+import android.widget.LinearLayout;
29
+import android.widget.ListView;
30
+import android.widget.SimpleAdapter;
31
+import android.widget.AdapterView.OnItemClickListener;
32
+
33
+public class PharmacyList extends Activity implements OnItemClickListener {
34
+	private Context context;
35
+	private SensorManager sm;
36
+	private ImageRotater arrowChangerSensor;
37
+	private ListView list;
38
+	private ScrollTextView tvLocation;
39
+
40
+	@Override
41
+    public void onCreate(Bundle savedInstanceState) {
42
+        super.onCreate(savedInstanceState);
43
+        setContentView(R.layout.list);
44
+        context = getApplicationContext();
45
+        
46
+        list = (ListView)findViewById(R.id.list);
47
+        sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
48
+        arrowChangerSensor = new ImageRotater();
49
+
50
+    	tvLocation = (ScrollTextView) findViewById(R.id.tvLocation);
51
+    	tvLocation.setText(getString(R.string.loading));
52
+    	tvLocation.setRndDuration(10000);
53
+        GeoUtils.getLocationName(context, new Handler(new Callback() {
54
+			@Override
55
+			public boolean handleMessage(Message msg) {
56
+		    	final String location = msg.getData().getString("location");
57
+		    	runOnUiThread(new Runnable() {
58
+					@Override
59
+					public void run() {
60
+				    	tvLocation.setText(location);
61
+					}
62
+				});
63
+		    	if (location.equals(getString(R.string.not_available))) {
64
+		    		final LinearLayout ll02 = (LinearLayout)findViewById(R.id.LinearLayout02);
65
+		    		TranslateAnimation anim = new TranslateAnimation(
66
+		    			      Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
67
+		    			      Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -1.0f
68
+		    			  );
69
+		    		anim.setAnimationListener(new AnimationListener() {
70
+		    			@Override
71
+						public void onAnimationStart(Animation animation) {
72
+						}
73
+						
74
+						@Override
75
+						public void onAnimationRepeat(Animation animation) {
76
+						}
77
+						
78
+						@Override
79
+						public void onAnimationEnd(Animation animation) {
80
+							ll02.setVisibility(View.GONE);
81
+						}
82
+					});
83
+		    		anim.setStartOffset(2000);
84
+		    		anim.setDuration(2000);
85
+		    		anim.setInterpolator(new AccelerateInterpolator(1));
86
+		    		ll02.startAnimation(anim);
87
+		    	} else
88
+			    	runOnUiThread(new Runnable() {
89
+						@Override
90
+						public void run() {
91
+					    	tvLocation.startScroll();
92
+						}
93
+					});
94
+		    	return true;
95
+			}
96
+		}));
97
+
98
+        list.setOnItemClickListener(this);
99
+        
100
+        LinkedList<Pharmacy> allPharm = GlobalVars.getPharmacies();
101
+		ArrayList<HashMap<String, String>> pharmacies = new ArrayList<HashMap<String, String>>();
102
+		for (Pharmacy p : allPharm) {
103
+			HashMap<String, String> pharmacy = new HashMap<String, String>();
104
+			pharmacy.put("name", p.getName());
105
+			pharmacy.put("addr", p.getAddress());
106
+			DecimalFormat df = new DecimalFormat("#.#");
107
+			double dist = Double.parseDouble(p.getDistance().substring(0, p.getDistance().indexOf("."))) / 1000;
108
+			pharmacy.put("dist",  df.format(dist) + "km");
109
+			pharmacies.add(pharmacy);
110
+		}
111
+		
112
+		/* Create the Adapter to show the information */
113
+		SimpleAdapter adap;
114
+		adap = new PharmacyListSimpleAdapter(context, pharmacies, R.layout.list_row,
115
+			new String[] {"name", "addr", "dist"},
116
+			new int[] {R.id.tvNome, R.id.tvMorada, R.id.tvDistancia},
117
+			arrowChangerSensor
118
+		);
119
+		list.setAdapter(adap);
120
+    }
121
+    
122
+    @Override
123
+    protected void onResume() {
124
+    	super.onResume();
125
+    	sm.registerListener(arrowChangerSensor, sm.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
126
+    }
127
+    
128
+    @Override
129
+    protected void onPause() {
130
+    	sm.unregisterListener(arrowChangerSensor);
131
+    	super.onPause();
132
+    }
133
+    
134
+    @Override
135
+	public void onItemClick(AdapterView<?> l, View v, int position, long id) {
136
+        Intent i = new Intent(getApplicationContext(), PharmacyInfo.class);
137
+        i.putExtra("org.r3pek.pharmacies.Pharmacy", GlobalVars.getPharmacies().get(position));
138
+        i.putExtra("org.r3pek.pharmacies.PharmacyIndex", position);
139
+        startActivity(i);
140
+    }
141
+    
142
+    @Override
143
+    public void onWindowFocusChanged(boolean hasFocus) {
144
+    	super.onWindowFocusChanged(hasFocus);
145
+    	tvLocation.startScroll();
146
+    }
147
+    
148
+}

+ 53
- 0
src/org/r3pek/pharmacies/PharmacyListSimpleAdapter.java View File

@@ -0,0 +1,53 @@
1
+package org.r3pek.pharmacies;
2
+
3
+import java.util.List;
4
+import java.util.Map;
5
+
6
+import org.r3pek.pharmacies.utils.GeoUtils;
7
+import org.r3pek.pharmacies.utils.GlobalVars;
8
+import org.r3pek.pharmacies.widgets.Arrow;
9
+import org.r3pek.pharmacies.widgets.ImageRotater;
10
+
11
+import android.content.Context;
12
+import android.view.View;
13
+import android.view.ViewGroup;
14
+import android.widget.ImageView;
15
+import android.widget.SimpleAdapter;
16
+import android.widget.TextView;
17
+
18
+public class PharmacyListSimpleAdapter extends SimpleAdapter {
19
+	private ImageRotater arrowCallback;
20
+
21
+	public PharmacyListSimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from,	int[] to, ImageRotater arrowCallback) {
22
+		super(context, data, resource, from, to);
23
+		this.arrowCallback = arrowCallback;
24
+	}
25
+		
26
+	private Pharmacy getPharmacyWithName(String name) {
27
+		for (Pharmacy p : GlobalVars.getPharmacies())
28
+			if (p.getName().equals(name)) return p;
29
+		
30
+		return null;
31
+	}
32
+
33
+	@Override
34
+	public View getView(int position, View convertView, ViewGroup parent) {
35
+		View v = super.getView(position, convertView, parent);
36
+		
37
+		ImageView ivStatus = (ImageView) v.findViewById(R.id.ivStatus);
38
+		Arrow ivDirection = (Arrow) v.findViewById(R.id.ivDirection);
39
+		TextView tvNome = (TextView) v.findViewById(R.id.tvNome);
40
+		Pharmacy p = getPharmacyWithName(tvNome.getText().toString());
41
+		
42
+		ivDirection.setBearing(GeoUtils.bearing(GlobalVars.positioner.getLastGeoPoint(), p.getGeoPoint()));
43
+		ivDirection.setOrientation(arrowCallback.getLastOrientation());
44
+		arrowCallback.addImage(ivDirection);
45
+		
46
+		if (p.isAtService())
47
+			ivStatus.setImageResource(R.drawable.status_on);
48
+		else
49
+			ivStatus.setImageResource(R.drawable.status_off);
50
+		
51
+		return v;
52
+	}
53
+}

+ 324
- 0
src/org/r3pek/pharmacies/ViewOnMap.java View File

@@ -0,0 +1,324 @@
1
+package org.r3pek.pharmacies;
2
+
3
+import java.net.URL;
4
+import java.util.List;
5
+
6
+import javax.xml.parsers.SAXParser;
7
+import javax.xml.parsers.SAXParserFactory;
8
+
9
+import org.r3pek.pharmacies.utils.GlobalVars;
10
+import org.r3pek.pharmacies.utils.OnPositionChangeListener;
11
+import org.r3pek.pharmacies.utils.Positioner;
12
+import org.xml.sax.InputSource;
13
+import org.xml.sax.XMLReader;
14
+
15
+import android.app.AlertDialog;
16
+import android.app.Dialog;
17
+import android.app.AlertDialog.Builder;
18
+import android.content.DialogInterface;
19
+import android.content.Intent;
20
+import android.os.Bundle;
21
+import android.os.Handler;
22
+import android.os.Message;
23
+import android.os.Handler.Callback;
24
+import android.provider.Settings;
25
+import android.view.LayoutInflater;
26
+import android.view.Menu;
27
+import android.view.MenuItem;
28
+import android.view.View;
29
+import android.view.ViewGroup;
30
+import android.widget.ImageView;
31
+import android.widget.Toast;
32
+
33
+import com.google.android.maps.GeoPoint;
34
+import com.google.android.maps.MapActivity;
35
+import com.google.android.maps.MapController;
36
+import com.google.android.maps.MapView;
37
+import com.google.android.maps.Overlay;
38
+
39
+public class ViewOnMap extends MapActivity implements OnPositionChangeListener {
40
+	private static final int MENU_REFRESH = 0;
41
+	private static final int MENU_SETTINGS = 1;
42
+	private static final int MENU_LIST = 2;
43
+	private static final int MENU_ABOUT = 3;
44
+	private static final int MENU_SETMYPOSITION = 4;
45
+	private static final int MENU_GETPOSITIONFROMGPS = 5;
46
+	private static final int MENU_MYPOSITION = 6;
47
+	
48
+	private static final int DIALOG_ABOUT = 0;
49
+	
50
+	private PharmaciesOverlay pharmaciesOverlay;
51
+	private MyPositionOverlay myPositionOverlay;
52
+	private MapView map;
53
+	private ConfigValues configs;
54
+	private Handler endThreadHandler;
55
+	private boolean hadFirstFix;
56
+
57
+    @Override
58
+    public void onCreate(Bundle savedInstanceState) {
59
+        super.onCreate(savedInstanceState);
60
+        setContentView(R.layout.map);
61
+        
62
+        /* Create objects */
63
+        map = (MapView)findViewById(R.id.MapView);
64
+        pharmaciesOverlay = new PharmaciesOverlay(getResources().getDrawable(R.drawable.pin_off), getApplicationContext(), map);
65
+        GlobalVars.pharmaciesOverlay = pharmaciesOverlay;
66
+        configs = new ConfigValues(getApplicationContext());
67
+        GlobalVars.positioner = new Positioner(getApplicationContext());
68
+        myPositionOverlay = new MyPositionOverlay(getApplicationContext(), map, this);
69
+        GlobalVars.getPharmacies().clear();
70
+        pharmaciesOverlay.refresh();
71
+        
72
+        /* Check if we have location providers enabled */ 
73
+        checkLocationProviders();
74
+        
75
+        /* Setup the map */
76
+        map.setBuiltInZoomControls(true);
77
+        map.setClickable(true);
78
+        map.setEnabled(true);
79
+        MapController mc = map.getController();
80
+        List<Overlay> mapOverlays = map.getOverlays();
81
+        mapOverlays.add(pharmaciesOverlay);
82
+        mapOverlays.add(myPositionOverlay);
83
+        mc.setZoom(15);
84
+        
85
+        /* Center view on ourselfs on first fix */
86
+        myPositionOverlay.runOnFirstFix(new Runnable() {
87
+			@Override
88
+			public void run() {
89
+				hadFirstFix = true;
90
+				GeoPoint p = GlobalVars.positioner.getLastGeoPoint();
91
+				populatePharmacies(p);
92
+				map.getController().animateTo(p);
93
+				runOnUiThread(new Runnable() {
94
+					public void run() {
95
+						Toast.makeText(getApplicationContext(), R.string.location_acquired, Toast.LENGTH_SHORT).show();
96
+					}
97
+				});
98
+			}
99
+		});
100
+
101
+        /* Create the handler for when we receive the Pharmacy list */ 
102
+        endThreadHandler = new Handler(new Callback() {
103
+			@Override
104
+			public boolean handleMessage(Message msg) {
105
+				if (msg.what == 0) {
106
+					pharmaciesOverlay.refresh();
107
+					map.postInvalidate();
108
+					map.setClickable(true);
109
+					if (GlobalVars.getPharmacies().size() == 0)
110
+						Toast.makeText(getApplicationContext(), R.string.not_pharmacies_returned, Toast.LENGTH_LONG).show();
111
+				} else
112
+					Toast.makeText(getApplicationContext(), R.string.error_getting_pharmacies, Toast.LENGTH_SHORT).show();
113
+				return true;
114
+			}
115
+		});
116
+        
117
+        hadFirstFix = false;
118
+    }
119
+    
120
+    private void checkLocationProviders() {
121
+        if (!GlobalVars.positioner.isLocalizationActive())
122
+            buildAlertMessageNoProviders();
123
+    }
124
+    
125
+    private void buildAlertMessageNoProviders() {
126
+        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
127
+        builder.setMessage(R.string.no_localization_active)
128
+               .setCancelable(false)
129
+               .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
130
+                   public void onClick(final DialogInterface dialog, final int id) {
131
+                       launchGPSOptions(); 
132
+                   }
133
+               })
134
+               .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
135
+                   public void onClick(final DialogInterface dialog, final int id) {
136
+                        dialog.cancel();
137
+                   }
138
+               });
139
+        final AlertDialog alert = builder.create();
140
+        alert.show();
141
+    }
142
+    
143
+    private void launchGPSOptions() {
144
+        final Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
145
+        startActivity(intent);
146
+    }
147
+    
148
+    public void onPause() {
149
+    	myPositionOverlay.disableMyLocation();
150
+    	GlobalVars.positioner.unregisterNotification(this);
151
+    	GlobalVars.positioner.cancelUpdates();
152
+    	super.onPause();
153
+    }
154
+    
155
+    public void onResume() {
156
+    	myPositionOverlay.enableMyLocation();
157
+    	GlobalVars.positioner.registerNotification(this);
158
+    	GlobalVars.positioner.requestUpdates();
159
+    	super.onResume();
160
+    }
161
+    
162
+    public boolean onCreateOptionsMenu(Menu menu) {
163
+        menu.add(0, MENU_REFRESH, 0, R.string.menu_refresh).setIcon(R.drawable.refresh);
164
+       	menu.add(0, MENU_GETPOSITIONFROMGPS, 0, R.string.menu_get_gps_pos).setIcon(R.drawable.gps);
165
+       	menu.add(0, MENU_SETMYPOSITION, 0, R.string.menu_set_my_location).setIcon(android.R.drawable.ic_menu_myplaces);
166
+       	menu.add(0, MENU_MYPOSITION, 0, R.string.menu_my_location).setIcon(android.R.drawable.ic_menu_mylocation);
167
+        menu.add(0, MENU_LIST, 0, R.string.menu_list).setIcon(android.R.drawable.ic_menu_agenda);
168
+        menu.add(0, MENU_SETTINGS, 0, R.string.menu_settings).setIcon(android.R.drawable.ic_menu_preferences);
169
+        menu.add(0, MENU_ABOUT, 0, R.string.menu_about).setIcon(android.R.drawable.ic_menu_info_details);;
170
+        return true;
171
+    }
172
+    
173
+    @Override
174
+    public boolean onPrepareOptionsMenu(Menu menu) {
175
+   		menu.findItem(MENU_REFRESH).setEnabled(hadFirstFix);
176
+   		menu.findItem(MENU_LIST).setEnabled(GlobalVars.getPharmacies().size() > 0);
177
+        if (GlobalVars.positioner.isFixedLocation()) {
178
+        	menu.findItem(MENU_GETPOSITIONFROMGPS).setVisible(true);
179
+        	menu.findItem(MENU_SETMYPOSITION).setVisible(false);
180
+        } else {
181
+        	menu.findItem(MENU_GETPOSITIONFROMGPS).setVisible(false);
182
+        	menu.findItem(MENU_SETMYPOSITION).setVisible(true);
183
+        }
184
+        menu.findItem(MENU_MYPOSITION).setEnabled(hadFirstFix);
185
+    	return true;
186
+    }
187
+    
188
+    public boolean onOptionsItemSelected(MenuItem item) {
189
+        switch (item.getItemId()) {
190
+	        case MENU_REFRESH:
191
+	        	populatePharmacies(GlobalVars.positioner.getLastGeoPoint());
192
+	            return true;
193
+	        case MENU_SETTINGS:
194
+	            startActivity(new Intent(getApplicationContext(), MyPreferences.class));
195
+	            return true;
196
+	        case MENU_LIST:
197
+	        	Intent i = new Intent(getApplicationContext(), PharmacyList.class);
198
+	            startActivity(i);
199
+	            return true;
200
+	        case MENU_ABOUT:
201
+	        	showDialog(DIALOG_ABOUT);
202
+	        	return true;
203
+	        case MENU_SETMYPOSITION:
204
+	        	setMyLocation();
205
+	        	return true;
206
+	        case MENU_GETPOSITIONFROMGPS:
207
+	        	getLocationFromGPS();
208
+	        	return true;
209
+	        case MENU_MYPOSITION:
210
+	        	gotoMyLocation();
211
+	        	return true;
212
+        }
213
+        return false;
214
+    }
215
+    
216
+    private void gotoMyLocation() {
217
+    	map.getController().animateTo(GlobalVars.positioner.getLastGeoPoint());
218
+    }
219
+    
220
+    private void setMyLocation() {
221
+        List<Overlay> mapOverlays = map.getOverlays();
222
+        pharmaciesOverlay.removeBallon();
223
+        mapOverlays.clear();
224
+        Handler h = new Handler(new Callback() {
225
+			@Override
226
+			public boolean handleMessage(Message msg) {
227
+				hadFirstFix = true;
228
+				GlobalVars.getPharmacies().clear();
229
+				pharmaciesOverlay.refresh();
230
+				populatePharmacies(GlobalVars.positioner.getLastGeoPoint());
231
+				return true;
232
+			}
233
+		});
234
+        mapOverlays.add(new GetPositionOverlay(null, pharmaciesOverlay, myPositionOverlay, h));
235
+        map.postInvalidate();
236
+        Toast.makeText(getApplicationContext(), R.string.tap_on_screen, Toast.LENGTH_LONG).show();
237
+    }
238
+    
239
+    private void getLocationFromGPS() {
240
+    	hadFirstFix = false;
241
+    	GlobalVars.positioner.cancelFixedLocation();
242
+    	GlobalVars.getPharmacies().clear();
243
+    	pharmaciesOverlay.refresh();
244
+    	map.postInvalidate();
245
+    	Toast.makeText(getApplicationContext(), R.string.now_from_GPS, Toast.LENGTH_SHORT).show();
246
+    }
247
+    
248
+	public void populatePharmacies(final GeoPoint curPos) {
249
+    	Runnable r = new Runnable() {
250
+			@Override
251
+			public void run() {
252
+		    	String service = configs.isOnlyService() ? "GetPharmaciesAtServiceByCoordinates" : "GetPharmaciesByCoordinates";
253
+		    	try {
254
+					URL url = new URL("http://services.sapo.pt/Pharmacy/" + service + "?latitude=" + (curPos.getLatitudeE6() / 1E6) + "&longitude=" + (curPos.getLongitudeE6() / 1E6) + "&radius=" + configs.getRadius());
255
+					
256
+					/* Get a SAXParser from the SAXPArserFactory. */ 
257
+					SAXParserFactory spf = SAXParserFactory.newInstance(); 
258
+					SAXParser sp = spf.newSAXParser(); 
259
+					
260
+					/* Get the XMLReader of the SAXParser we created. */ 
261
+					XMLReader xr = sp.getXMLReader(); 
262
+					/* Create a new ContentHandler and apply it to the XML-Reader*/ 
263
+					XMLParserHandler handler = new XMLParserHandler();
264
+					xr.setContentHandler(handler);
265
+					
266
+					/* Parse the xml-data from our URL. */
267
+					xr.parse(new InputSource(url.openStream()));
268
+					/* Parsing has finished. */
269
+					
270
+					GlobalVars.getPharmacies().clear();
271
+					pharmaciesOverlay.refresh();
272
+					/* Check if server returned an error */
273
+					if (handler.getPharmacies() == null) {
274
+						endThreadHandler.sendEmptyMessage(1);
275
+						return;
276
+					}
277
+					
278
+					/* Our XMLParserHandler now provides the parsed data to us. */
279
+					for (Pharmacy p : handler.getPharmacies())
280
+						GlobalVars.getPharmacies().add(p);
281
+					pharmaciesOverlay.refresh();
282
+					
283
+					endThreadHandler.sendEmptyMessage(0);
284
+		    	} catch (Exception e) { endThreadHandler.sendEmptyMessage(1); }
285
+			}
286
+		};
287
+		Thread t = new Thread(r);
288
+		t.start();
289
+    }
290
+    
291
+    @Override
292
+	protected boolean isRouteDisplayed() {
293
+		return false;
294
+	}
295
+    
296
+    public Dialog onCreateDialog(int id) {
297
+    	Dialog d;
298
+    	switch (id) {
299
+    		case DIALOG_ABOUT: {
300
+    			LayoutInflater inflater = (LayoutInflater)getApplicationContext().getSystemService(LAYOUT_INFLATER_SERVICE);
301
+    			View layout = inflater.inflate(R.layout.about, (ViewGroup)findViewById(R.id.aboutRoot));
302
+    			ImageView image = (ImageView)layout.findViewById(R.id.ImageView01);
303
+    			image.setImageResource(R.drawable.icon);
304
+    			Builder builder = new AlertDialog.Builder(this);
305
+    			builder.setView(layout);
306
+    			d = builder.create();
307
+    			break;
308
+    		}
309
+    		default: d = null;
310
+    	}
311
+    	return d;
312
+    }
313
+
314
+	@Override
315
+	public void onLocationChange(GeoPoint currentPos, float accuracy) {
316
+		if (!hadFirstFix) {
317
+			map.getController().animateTo(currentPos);
318
+			populatePharmacies(currentPos);
319
+			hadFirstFix = true;
320
+		}
321
+		map.postInvalidate();
322
+	}
323
+	
324
+}

+ 111
- 0
src/org/r3pek/pharmacies/XMLParserHandler.java View File

@@ -0,0 +1,111 @@
1
+package org.r3pek.pharmacies;
2
+
3
+import java.util.ArrayList;
4
+
5
+import org.xml.sax.Attributes;
6
+import org.xml.sax.helpers.DefaultHandler;
7
+
8
+public class XMLParserHandler extends DefaultHandler {
9
+	private boolean inName = false;
10
+	private boolean inAddress = false;
11
+	private boolean inZipCode = false;
12
+	private boolean inMunicipality = false;
13
+	private boolean inLatitude = false;
14
+	private boolean inLongitude = false;
15
+	private boolean inPhone = false;
16
+	private boolean inDistance = false;
17
+	private boolean inIsAtService = false;
18
+	private boolean inParish = false;
19
+	private boolean error = false;
20
+	private boolean inErrorMessage;
21
+	private String errorMessage;
22
+	
23
+	private Pharmacy currentPharmacy;
24
+	
25
+	private ArrayList<Pharmacy> result;
26
+	
27
+	public XMLParserHandler() {
28
+		result = new ArrayList<Pharmacy>();
29
+	}
30
+	
31
+	private void checkTag(String tag, boolean newValue) {
32
+		if ((tag.equals("GetPharmaciesByCoordinatesResponse") || tag.equals("GetPharmaciesAtServiceByCoordinatesResponse")) && newValue) {
33
+			if (error) error = false;
34
+			result.clear();
35
+		} else if (tag.equals("Pharmacy")) {
36
+			if (newValue)
37
+				currentPharmacy = new Pharmacy();
38
+			else 
39
+				result.add(currentPharmacy);
40
+		} else if (tag.equals("Name"))
41
+			inName = newValue;
42
+		else if (tag.equals("Street"))
43
+			inAddress = newValue;
44
+		else if (tag.equals("ZipCode"))
45
+			inZipCode = newValue;
46
+		else if (tag.equals("Municipality"))
47
+			inMunicipality = newValue;
48
+		else if (tag.equals("Latitude"))
49
+			inLatitude = newValue;
50
+		else if (tag.equals("Longitude"))
51
+			inLongitude = newValue;
52
+		else if (tag.equals("Phone"))
53
+			inPhone = newValue;
54
+		else if (tag.equals("Distance"))
55
+			inDistance = newValue;
56
+		else if (tag.equals("IsAtService"))
57
+			inIsAtService = newValue;
58
+		else if (tag.equals("Parish"))
59
+			inParish = newValue;
60
+		else if (tag.equals("Fault"))
61
+			error = true;
62
+		else if (tag.equals("FaultString"))
63
+			inErrorMessage = newValue; 
64
+	}
65
+	
66
+	public void startElement(String uri, String name, String qName, Attributes atts) {
67
+		checkTag(name.trim(), true);
68
+	}
69
+
70
+	public void endElement(String uri, String name, String qName) {
71
+		checkTag(name.trim(), false);
72
+	}
73
+	
74
+	public void characters(char ch[], int start, int length) {
75
+		String chars = (new String(ch).substring(start, start + length));
76
+		
77
+		if (inName)
78
+			currentPharmacy.setName(currentPharmacy.getName() + chars);
79
+		else if (inAddress)
80
+			currentPharmacy.setAddress(currentPharmacy.getAddress() + chars);
81
+		else if (inZipCode)
82
+			currentPharmacy.setAddress(currentPharmacy.getAddress() + "\n" + chars);
83
+		else if (inMunicipality)
84
+			currentPharmacy.setAddress(currentPharmacy.getAddress() + " " + chars);
85
+		else if (inLatitude)
86
+			currentPharmacy.setLatitude(currentPharmacy.getLatitude() + chars);
87
+		else if (inLongitude)
88
+			currentPharmacy.setLongitude(currentPharmacy.getLongitude() + chars);
89
+		else if (inPhone)
90
+			currentPharmacy.setPhoneNumber(currentPharmacy.getPhoneNumber() + chars);
91
+		else if (inDistance)
92
+			currentPharmacy.setDistance(currentPharmacy.getDistance() + chars);
93
+		else if (inIsAtService)
94
+			currentPharmacy.setAtService(Boolean.parseBoolean(chars));
95
+		else if (inParish)
96
+			currentPharmacy.setParish(currentPharmacy.getParish() + chars);
97
+		else if (inErrorMessage)
98
+			errorMessage += chars;
99
+	}
100
+	
101
+	public ArrayList<Pharmacy> getPharmacies() {
102
+		if (error) return null;
103
+		
104
+		return result;
105
+	}
106
+	
107
+	public String getErrorMessage() {
108
+		return errorMessage;
109
+	}
110
+	
111
+}

+ 121
- 0
src/org/r3pek/pharmacies/utils/GeoUtils.java View File

@@ -0,0 +1,121 @@
1
+package org.r3pek.pharmacies.utils;
2
+
3
+/* 
4
+ * Copyright (C) 2008 Google Inc. 
5
+ * 
6
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
7
+ * you may not use this file except in compliance with the License. 
8
+ * You may obtain a copy of the License at 
9
+ * 
10
+ *      http://www.apache.org/licenses/LICENSE-2.0 
11
+ * 
12
+ * Unless required by applicable law or agreed to in writing, software 
13
+ * distributed under the License is distributed on an "AS IS" BASIS, 
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
15
+ * See the License for the specific language governing permissions and 
16
+ * limitations under the License. 
17
+ */ 
18
+
19
+import java.io.IOException;
20
+import java.util.List;
21
+
22
+import org.r3pek.pharmacies.R;
23
+
24
+import android.content.Context;
25
+import android.location.Address;
26
+import android.location.Geocoder;
27
+import android.os.Bundle;
28
+import android.os.Handler;
29
+import android.os.Message;
30
+
31
+import com.google.android.maps.GeoPoint;
32
+
33
+/** 
34
+ * Library for some use useful latitude/longitude math 
35
+ */ 
36
+public class GeoUtils { 
37
+    
38
+    private static double MILLION = 1000000;  
39
+    /** 
40
+     * Computes the bearing in degrees between two points on Earth. 
41
+     * 
42
+     * @param lat1 Latitude of the first point 
43
+     * @param lon1 Longitude of the first point 
44
+     * @param lat2 Latitude of the second point 
45
+     * @param lon2 Longitude of the second point 
46
+     * @return Bearing between the two points in degrees. A value of 0 means due 
47
+     *         north. 
48
+     */ 
49
+    public static float bearing(double lat1, double lon1, double lat2, double lon2) { 
50
+        double lat1Rad = Math.toRadians(lat1); 
51
+        double lat2Rad = Math.toRadians(lat2); 
52
+        double deltaLonRad = Math.toRadians(lon2 - lon1); 
53
+
54
+        double y = Math.sin(deltaLonRad) * Math.cos(lat2Rad); 
55
+        double x = Math.cos(lat1Rad) * Math.sin(lat2Rad) - Math.sin(lat1Rad) * Math.cos(lat2Rad) 
56
+                * Math.cos(deltaLonRad); 
57
+        return radToBearing(Math.atan2(y, x)); 
58
+    } 
59
+    
60
+    /** 
61
+     * Computes the bearing in degrees between two points on Earth. 
62
+     * 
63
+     * @param p1 First point 
64
+     * @param p2 Second point 
65
+     * @return Bearing between the two points in degrees. A value of 0 means due 
66
+     *         north. 
67
+     */ 
68
+    public static float bearing(GeoPoint p1, GeoPoint p2) { 
69
+        double lat1 = p1.getLatitudeE6() / MILLION; 
70
+        double lon1 = p1.getLongitudeE6() / MILLION; 
71
+        double lat2 = p2.getLatitudeE6() / MILLION; 
72
+        double lon2 = p2.getLongitudeE6() / MILLION; 
73
+
74
+        return bearing(lat1, lon1, lat2, lon2); 
75
+    } 
76
+    
77
+    
78
+    /** 
79
+     * Converts an angle in radians to degrees 
80
+     */ 
81
+    public static float radToBearing(double rad) { 
82
+        return (float) ((Math.toDegrees(rad) + 360) % 360); 
83
+    }
84
+    
85
+    
86
+    /**
87
+     * Returns the current's location address
88
+     */
89
+    public static void getLocationName(final Context context, final Handler h) {
90
+    	Runnable r = new Runnable() {
91
+			@Override
92
+			public void run() {
93
+		    	Geocoder g = new Geocoder(context);
94
+		    	Message m = new Message();
95
+		    	Bundle b = new Bundle();
96
+		    	List<Address> addresses = null;
97
+		    	try {
98
+					addresses = g.getFromLocation(GlobalVars.positioner.getLastLocation().getLatitude(), GlobalVars.positioner.getLastLocation().getLongitude(), 1);
99
+				} catch (IOException e) { }
100
+				if (addresses == null || addresses.size() == 0) {
101
+					b.putString("location", context.getString(R.string.not_available));
102
+					m.setData(b);
103
+					h.dispatchMessage(m);
104
+				}
105
+				
106
+				String result = "";
107
+				for (int i = 0; i <= addresses.get(0).getMaxAddressLineIndex(); i++)
108
+					result += addresses.get(0).getAddressLine(i) + ", ";
109
+
110
+				if (result.equals(""))
111
+					b.putString("location", context.getString(R.string.not_available));
112
+				else
113
+					b.putString("location", result.substring(0, result.length() - 2));
114
+				m.setData(b);
115
+				h.dispatchMessage(m);
116
+			}
117
+		};
118
+		Thread t = new Thread(r);
119
+		t.start();
120
+    }
121
+} 

+ 19
- 0
src/org/r3pek/pharmacies/utils/GlobalVars.java View File

@@ -0,0 +1,19 @@
1
+package org.r3pek.pharmacies.utils;
2
+
3
+import java.util.LinkedList;
4
+
5
+import org.r3pek.pharmacies.PharmaciesOverlay;
6
+import org.r3pek.pharmacies.Pharmacy;
7
+
8
+public class GlobalVars {
9
+	public static Positioner positioner;
10
+	public static PharmaciesOverlay pharmaciesOverlay;
11
+	
12
+	private static LinkedList<Pharmacy> pharmacies;
13
+	
14
+	public synchronized static LinkedList<Pharmacy> getPharmacies() {
15
+		if (pharmacies == null)
16
+			pharmacies = new LinkedList<Pharmacy>();
17
+		return pharmacies;
18
+	}
19
+}

+ 9
- 0
src/org/r3pek/pharmacies/utils/OnPositionChangeListener.java View File

@@ -0,0 +1,9 @@
1
+package org.r3pek.pharmacies.utils;
2
+
3
+import com.google.android.maps.GeoPoint;
4
+
5
+public interface OnPositionChangeListener {
6
+	
7
+	void onLocationChange(GeoPoint currentPos, float accuracy);
8
+
9
+}

+ 175
- 0
src/org/r3pek/pharmacies/utils/Positioner.java View File

@@ -0,0 +1,175 @@
1
+package org.r3pek.pharmacies.utils;
2
+
3
+import java.util.LinkedList;
4
+
5
+import android.content.Context;
6
+import android.location.Location;
7
+import android.location.LocationListener;
8
+import android.location.LocationManager;
9
+import android.os.Bundle;
10
+import android.util.Log;
11
+
12
+import com.google.android.maps.GeoPoint;
13
+
14
+public class Positioner implements LocationListener {
15
+	private Location currentLocation;
16
+	private GeoPoint currentGeoPoint;
17
+	private float currentAccuracy;
18
+	private LinkedList<OnPositionChangeListener> toNotify;
19
+	private LocationManager locationManager;
20
+	private boolean isUpdating;
21
+	private boolean hadGPSFix;
22
+	private boolean isFixedLocation;
23
+	private boolean isGPSFix;
24
+	
25
+	public Positioner(Context context) {
26
+		toNotify = new LinkedList<OnPositionChangeListener>();
27
+		locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
28
+		isUpdating = false;
29
+		hadGPSFix = false;
30
+		isFixedLocation = false;
31
+		isGPSFix = false;
32
+		initLocation();
33
+		requestUpdates();
34
+	}
35
+	
36
+	private void initLocation() {
37
+		if (!isLocalizationActive()) return;
38
+		Location loc_net = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
39
+		Location loc_gps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
40
+		Location loc = loc_gps == null ? loc_net : loc_gps;
41
+		if (loc == null) return;
42
+		
43
+		currentLocation = loc;
44
+		currentGeoPoint = new GeoPoint((int)(loc.getLatitude() * 1E6), 
45
+				(int)(loc.getLongitude() * 1E6));
46
+		currentAccuracy = loc.getAccuracy();
47
+		notifyAllClients();
48
+	}
49
+	
50
+	private String getBestLocationProvider() {
51
+		if (!isLocalizationActive())
52
+			return LocationManager.GPS_PROVIDER;
53
+		else if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
54
+				return LocationManager.GPS_PROVIDER;
55
+		else return LocationManager.NETWORK_PROVIDER;
56
+	}
57
+	
58
+	public void requestUpdates() {
59
+		if (isUpdating) return;
60
+		Log.d("Positioner", "Enabling location Updates");
61
+
62
+		if (getBestLocationProvider().equals(LocationManager.GPS_PROVIDER) && !hadGPSFix)
63
+			locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
64
+		locationManager.requestLocationUpdates(getBestLocationProvider(), 0, 0, this);
65
+		
66
+		isUpdating = true;
67
+	}
68
+	
69
+	public void cancelUpdates() {
70
+		if (!isUpdating) return;
71
+		Log.d("Positioner", "Disabling location Updates");
72
+
73
+		locationManager.removeUpdates(this);
74
+		
75
+		isUpdating = false;
76
+	}
77
+	
78
+	public boolean isLocalizationActive() {
79
+    	return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || 
80
+    		locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
81
+	}