Bump java library versions
[fw/altos] / altosdroid / src / org / altusmetrum / AltosDroid / PreloadMapActivity.java
1 /*
2  * Copyright © 2015 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 package org.altusmetrum.AltosDroid;
19
20 import java.util.*;
21 import java.io.*;
22 import java.text.*;
23
24 import org.altusmetrum.AltosDroid.R;
25
26 import android.app.Activity;
27 import android.bluetooth.BluetoothAdapter;
28 import android.bluetooth.BluetoothDevice;
29 import android.content.BroadcastReceiver;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.os.Bundle;
34 import android.view.View;
35 import android.view.Window;
36 import android.view.View.OnClickListener;
37 import android.widget.*;
38 import android.widget.AdapterView.*;
39 import android.location.Location;
40 import android.location.LocationManager;
41 import android.location.LocationListener;
42 import android.location.Criteria;
43
44 import org.altusmetrum.altoslib_11.*;
45
46 /**
47  * This Activity appears as a dialog. It lists any paired devices and
48  * devices detected in the area after discovery. When a device is chosen
49  * by the user, the MAC address of the device is sent back to the parent
50  * Activity in the result Intent.
51  */
52 public class PreloadMapActivity extends Activity implements AltosLaunchSiteListener, AltosMapLoaderListener, LocationListener {
53
54         private ArrayAdapter<AltosLaunchSite> known_sites_adapter;
55
56         private CheckBox        hybrid;
57         private CheckBox        satellite;
58         private CheckBox        roadmap;
59         private CheckBox        terrain;
60
61         private Spinner         known_sites_spinner;
62         private Spinner         min_zoom;
63         private Spinner         max_zoom;
64         private TextView        radius_label;
65         private Spinner         radius;
66
67         private EditText        latitude;
68         private EditText        longitude;
69
70         private ProgressBar     progress;
71
72         private AltosMapLoader  loader;
73
74         long    loader_notify_time;
75
76         /* AltosMapLoaderListener interfaces */
77         public void loader_start(final int max) {
78                 loader_notify_time = System.currentTimeMillis();
79
80                 this.runOnUiThread(new Runnable() {
81                                 public void run() {
82                                         progress.setMax(max);
83                                         progress.setProgress(0);
84                                 }
85                         });
86         }
87
88         public void loader_notify(final int cur, final int max, final String name) {
89                 long    now = System.currentTimeMillis();
90
91                 if (now - loader_notify_time < 100)
92                         return;
93
94                 loader_notify_time = now;
95
96                 this.runOnUiThread(new Runnable() {
97                                 public void run() {
98                                         progress.setProgress(cur);
99                                 }
100                         });
101         }
102
103         public void loader_done(int max) {
104                 loader = null;
105                 this.runOnUiThread(new Runnable() {
106                                 public void run() {
107                                         progress.setProgress(0);
108                                         finish();
109                                 }
110                         });
111         }
112
113         public void debug(String format, Object ... arguments) {
114                 AltosDebug.debug(format, arguments);
115         }
116
117         /* AltosLaunchSiteListener interface */
118
119         public void notify_launch_sites(final List<AltosLaunchSite> sites) {
120                 this.runOnUiThread(new Runnable() {
121                                 public void run() {
122                                         for (AltosLaunchSite site : sites)
123                                                 known_sites_adapter.add(site);
124                                 }
125                         });
126         }
127
128         /* LocationProvider interface */
129
130         AltosLaunchSite current_location_site;
131
132         public void onLocationChanged(Location location) {
133                 AltosDebug.debug("location changed");
134                 if (current_location_site == null) {
135                         AltosLaunchSite selected_item = (AltosLaunchSite) known_sites_spinner.getSelectedItem();
136
137                         current_location_site = new AltosLaunchSite("Current Location", location.getLatitude(), location.getLongitude());
138                         known_sites_adapter.insert(current_location_site, 0);
139
140                         if (selected_item != null)
141                                 known_sites_spinner.setSelection(known_sites_adapter.getPosition(selected_item));
142                         else {
143                                 latitude.setText(new StringBuffer(String.format("%12.6f", current_location_site.latitude)));
144                                 longitude.setText(new StringBuffer(String.format("%12.6f", current_location_site.longitude)));
145                         }
146                 } else {
147                         current_location_site.latitude = location.getLatitude();
148                         current_location_site.longitude = location.getLongitude();
149                 }
150         }
151
152         public void onStatusChanged(String provider, int status, Bundle extras) {
153         }
154
155         public void onProviderEnabled(String provider) {
156         }
157
158         public void onProviderDisabled(String provider) {
159         }
160
161         private double text(EditText view) throws ParseException {
162                 return AltosParse.parse_double_locale(view.getEditableText().toString());
163         }
164
165         private double latitude() throws ParseException {
166                 return text(latitude);
167         }
168
169         private double longitude() throws ParseException {
170                 return text(longitude);
171         }
172
173         private int value(Spinner spinner) {
174                 return (Integer) spinner.getSelectedItem();
175         }
176
177         private int min_z() {
178                 return value(min_zoom);
179         }
180
181         private int max_z() {
182                 return value(max_zoom);
183         }
184
185         private double value_distance(Spinner spinner) {
186                 return (Double) spinner.getSelectedItem();
187         }
188
189         private double radius() {
190                 double r = value_distance(radius);
191                 if (AltosPreferences.imperial_units())
192                         r = AltosConvert.miles_to_meters(r);
193                 else
194                         r = r * 1000;
195                 return r;
196         }
197
198         private int bit(CheckBox box, int value) {
199                 if (box.isChecked())
200                         return 1 << value;
201                 return 0;
202         }
203
204         private int types() {
205                 return (bit(hybrid, AltosMap.maptype_hybrid) |
206                         bit(satellite, AltosMap.maptype_satellite) |
207                         bit(roadmap, AltosMap.maptype_roadmap) |
208                         bit(terrain, AltosMap.maptype_terrain));
209         }
210
211         private void load() {
212                 if (loader != null)
213                         return;
214
215                 try {
216                         double  lat = latitude();
217                         double  lon = longitude();
218                         int     min = min_z();
219                         int     max = max_z();
220                         double  r = radius();
221                         int     t = types();
222
223                         AltosDebug.debug("PreloadMap load %f %f %d %d %f %d\n",
224                                          lat, lon, min, max, r, t);
225                         loader = new AltosMapLoader(this, lat, lon, min, max, r, t, AltosMapOffline.scale);
226                 } catch (ParseException e) {
227                         AltosDebug.debug("PreloadMap load raised exception %s", e.toString());
228                 }
229         }
230
231         private void add_numbers(Spinner spinner, int min, int max, int def) {
232
233                 ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(this, android.R.layout.simple_spinner_item);
234
235                 int     spinner_def = 0;
236                 int     pos = 0;
237
238                 for (int i = min; i <= max; i++) {
239                         adapter.add(new Integer(i));
240                         if (i == def)
241                                 spinner_def = pos;
242                         pos++;
243                 }
244
245                 spinner.setAdapter(adapter);
246                 spinner.setSelection(spinner_def);
247         }
248
249
250         private void add_distance(Spinner spinner, double[] distances_km, double def_km, double[] distances_mi, double def_mi) {
251
252                 ArrayAdapter<Double> adapter = new ArrayAdapter<Double>(this, android.R.layout.simple_spinner_item);
253
254                 int     spinner_def = 0;
255                 int     pos = 0;
256
257                 double[] distances;
258                 double  def;
259                 if (AltosPreferences.imperial_units()) {
260                         distances = distances_mi;
261                         def = def_mi;
262                 } else {
263                         distances = distances_km;
264                         def = def_km;
265                 }
266
267                 for (int i = 0; i < distances.length; i++) {
268                         adapter.add(distances[i]);
269                         if (distances[i] == def)
270                                 spinner_def = pos;
271                         pos++;
272                 }
273
274                 spinner.setAdapter(adapter);
275                 spinner.setSelection(spinner_def);
276         }
277
278
279
280         class SiteListListener implements OnItemSelectedListener {
281                 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
282                         AltosLaunchSite site = (AltosLaunchSite) parent.getItemAtPosition(pos);
283                         latitude.setText(new StringBuffer(String.format("%12.6f", site.latitude)));
284                         longitude.setText(new StringBuffer(String.format("%12.6f", site.longitude)));
285                 }
286                 public void onNothingSelected(AdapterView<?> parent) {
287                 }
288
289                 public SiteListListener() {
290                 }
291         }
292
293         double[]        radius_mi = { 1, 2, 5, 10, 20 };
294         double          radius_def_mi = 2;
295         double[]        radius_km = { 1, 2, 5, 10, 20, 30 };
296         double          radius_def_km = 2;
297
298         @Override
299         protected void onCreate(Bundle savedInstanceState) {
300                 super.onCreate(savedInstanceState);
301
302                 // Setup the window
303                 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
304                 setContentView(R.layout.map_preload);
305
306                 // Set result CANCELED incase the user backs out
307                 setResult(Activity.RESULT_CANCELED);
308
309                 // Initialize the button to perform device discovery
310                 Button loadButton = (Button) findViewById(R.id.preload_load);
311                 loadButton.setOnClickListener(new OnClickListener() {
312                         public void onClick(View v) {
313                                 load();
314                         }
315                 });
316
317                 latitude = (EditText) findViewById(R.id.preload_latitude);
318                 longitude = (EditText) findViewById(R.id.preload_longitude);
319
320                 hybrid = (CheckBox) findViewById(R.id.preload_hybrid);
321                 satellite = (CheckBox) findViewById(R.id.preload_satellite);
322                 roadmap = (CheckBox) findViewById(R.id.preload_roadmap);
323                 terrain = (CheckBox) findViewById(R.id.preload_terrain);
324
325                 hybrid.setChecked(true);
326
327                 min_zoom = (Spinner) findViewById(R.id.preload_min_zoom);
328                 add_numbers(min_zoom,
329                             AltosMap.min_zoom - AltosMap.default_zoom,
330                             AltosMap.max_zoom - AltosMap.default_zoom, -2);
331                 max_zoom = (Spinner) findViewById(R.id.preload_max_zoom);
332                 add_numbers(max_zoom,
333                             AltosMap.min_zoom - AltosMap.default_zoom,
334                             AltosMap.max_zoom - AltosMap.default_zoom, 2);
335                 radius_label = (TextView) findViewById(R.id.preload_radius_label);
336                 radius = (Spinner) findViewById(R.id.preload_radius);
337                 if (AltosPreferences.imperial_units())
338                         radius_label.setText("Radius (miles)");
339                 else
340                         radius_label.setText("Radius (km)");
341                 add_distance(radius, radius_km, radius_def_km, radius_mi, radius_def_mi);
342
343                 progress = (ProgressBar) findViewById(R.id.preload_progress);
344
345                 // Initialize array adapters. One for already paired devices and
346                 // one for newly discovered devices
347                 known_sites_spinner = (Spinner) findViewById(R.id.preload_site_list);
348
349                 known_sites_adapter = new ArrayAdapter<AltosLaunchSite>(this, android.R.layout.simple_spinner_item);
350
351                 known_sites_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
352
353                 known_sites_spinner.setAdapter(known_sites_adapter);
354                 known_sites_spinner.setOnItemSelectedListener(new SiteListListener());
355
356                 // Listen for GPS and Network position updates
357                 LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
358
359                 locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
360
361                 new AltosLaunchSites(this);
362         }
363
364         @Override
365         protected void onDestroy() {
366                 super.onDestroy();
367
368                 if (loader != null)
369                         loader.abort();
370
371                 // Stop listening for location updates
372                 ((LocationManager) getSystemService(Context.LOCATION_SERVICE)).removeUpdates(this);
373         }
374 }