Bump java lib versions in preparation for 1.9.2
[fw/altos] / altosdroid / app / src / main / java / org / altusmetrum / AltosDroid / IgniterActivity.java
1 /*
2  * Copyright © 2016 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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 package org.altusmetrum.AltosDroid;
20
21 import java.lang.ref.WeakReference;
22 import java.util.*;
23
24 import android.app.Activity;
25 import android.content.*;
26 import android.graphics.*;
27 import android.os.*;
28 import android.view.*;
29 import android.view.View.*;
30 import android.widget.*;
31
32 import org.altusmetrum.altoslib_14.*;
33
34 class IgniterItem {
35         public String name;
36         public String pretty;
37         public String status;
38         public LinearLayout igniter_view = null;
39         public TextView pretty_view = null;
40         public TextView status_view = null;
41
42         private void update() {
43                 if (pretty_view != null)
44                         pretty_view.setText(pretty);
45                 if (status_view != null)
46                         status_view.setText(status);
47         }
48
49         public void set(String name, String pretty, String status) {
50                 if (!name.equals(this.name) ||
51                     !pretty.equals(this.pretty) ||
52                     !status.equals(this.status))
53                 {
54                         this.name = name;
55                         this.pretty = pretty;
56                         this.status = status;
57                         update();
58                 }
59         }
60
61         public void realize(LinearLayout igniter_view,
62                             TextView pretty_view,
63                             TextView status_view) {
64                 if (igniter_view != this.igniter_view ||
65                     pretty_view != this.pretty_view ||
66                     status_view != this.status_view)
67                 {
68                         this.igniter_view = igniter_view;
69                         this.pretty_view = pretty_view;
70                         this.status_view = status_view;
71                         update();
72                 }
73         }
74
75         public IgniterItem() {
76         }
77 }
78
79 class IgniterAdapter extends ArrayAdapter<IgniterItem> {
80         int resource;
81         int selected_item = -1;
82
83         public IgniterAdapter(Context context, int in_resource) {
84                 super(context, in_resource);
85                 resource = in_resource;
86         }
87
88         @Override
89         public View getView(int position, View convertView, ViewGroup parent) {
90                 IgniterItem item = getItem(position);
91                 if (item.igniter_view == null) {
92                         LinearLayout igniter_view = new LinearLayout(getContext());
93                         String inflater = Context.LAYOUT_INFLATER_SERVICE;
94                         LayoutInflater li = (LayoutInflater) getContext().getSystemService(inflater);
95                         li.inflate(resource, igniter_view, true);
96
97                         item.realize(igniter_view,
98                                      (TextView) igniter_view.findViewById(R.id.igniter_name),
99                                      (TextView) igniter_view.findViewById(R.id.igniter_status));
100                 }
101                 if (position == selected_item)
102                         item.igniter_view.setBackgroundColor(Color.RED);
103                 else
104                         item.igniter_view.setBackgroundColor(0);
105                 return item.igniter_view;
106         }
107 }
108
109 public class IgniterActivity extends Activity {
110         private ListView igniters_view;
111         private ToggleButton arm;
112         private Button fire;
113
114         private HashMap<String,IgniterItem> igniters = new HashMap<String,IgniterItem>();;
115
116         private IgniterAdapter igniters_adapter;
117
118         private boolean is_bound;
119         private Messenger service = null;
120         private final Messenger messenger = new Messenger(new IncomingHandler(this));
121
122         private Timer query_timer;
123         private boolean query_timer_running;
124
125         private Timer arm_timer;
126         private int arm_remaining;
127
128         public static final int IGNITER_QUERY = 1;
129         public static final int IGNITER_FIRE = 2;
130
131         // The Handler that gets information back from the Telemetry Service
132         static class IncomingHandler extends Handler {
133                 private final WeakReference<IgniterActivity> igniter_activity;
134                 IncomingHandler(IgniterActivity ia) { igniter_activity = new WeakReference<IgniterActivity>(ia); }
135
136                 @Override
137                 public void handleMessage(Message msg) {
138                         IgniterActivity ia = igniter_activity.get();
139
140                         switch (msg.what) {
141                         case AltosDroid.MSG_IGNITER_STATUS:
142                                 @SuppressWarnings("unchecked") HashMap<String,Integer> map = (HashMap <String,Integer>) msg.obj;
143                                 ia.igniter_status(map);
144                                 break;
145                         }
146                 }
147         };
148
149
150         private ServiceConnection connection = new ServiceConnection() {
151                 public void onServiceConnected(ComponentName className, IBinder binder) {
152                         service = new Messenger(binder);
153                         query_timer_tick();
154                 }
155
156                 public void onServiceDisconnected(ComponentName className) {
157                         // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
158                         service = null;
159                 }
160         };
161
162         void doBindService() {
163                 bindService(new Intent(this, TelemetryService.class), connection, Context.BIND_AUTO_CREATE);
164                 is_bound = true;
165         }
166
167         void doUnbindService() {
168                 if (is_bound) {
169                         // If we have received the service, and hence registered with it, then now is the time to unregister.
170                         unbindService(connection);
171                         is_bound = false;
172                 }
173         }
174
175         private void done() {
176                 Intent intent = new Intent();
177                 setResult(Activity.RESULT_OK, intent);
178                 finish();
179         }
180
181         class FireThread extends Thread {
182                 private final String igniter;
183
184                 @Override
185                 public void run() {
186                         Message msg = Message.obtain(null, TelemetryService.MSG_IGNITER_FIRE, igniter);
187                         try {
188                                 service.send(msg);
189                         } catch (RemoteException re) {
190                         }
191                 }
192
193                 public FireThread(String igniter) {
194                         this.igniter = igniter;
195                 }
196         }
197
198         private void fire_igniter() {
199                 if (igniters_adapter.selected_item >= 0) {
200                         IgniterItem     item = igniters_adapter.getItem(igniters_adapter.selected_item);
201                         FireThread      ft = new FireThread(item.name);
202                         ft.run();
203                         arm.setChecked(false);
204                 }
205         }
206
207         private void arm_igniter(boolean is_checked) {
208                 if (is_checked) {
209                         arm_timer_stop();
210                         arm_timer = new Timer();
211                         arm_remaining = 10;
212                         arm_set_text();
213                         fire.setEnabled(true);
214                         arm_timer.scheduleAtFixedRate(new TimerTask() {
215                                         public void run() {
216                                                 arm_timer_tick();
217                                         }},
218                                 1000L, 1000L);
219                 } else {
220                         arm_timer_stop();
221                         fire.setEnabled(false);
222                 }
223         }
224
225         private synchronized void query_timer_tick() {
226                 if (query_timer_running)
227                         return;
228                 if (service == null)
229                         return;
230                 query_timer_running = true;
231                 Thread thread = new Thread(new Runnable() {
232                                 public void run() {
233                                         try {
234                                                 Message msg = Message.obtain(null, TelemetryService.MSG_IGNITER_QUERY);
235                                                 msg.replyTo = messenger;
236                                                 if (service == null) {
237                                                         synchronized(IgniterActivity.this) {
238                                                                 query_timer_running = false;
239                                                         }
240                                                 } else
241                                                         service.send(msg);
242                                         } catch (RemoteException re) {
243                                                 AltosDebug.debug("igniter query thread failed");
244                                                 synchronized(IgniterActivity.this) {
245                                                         query_timer_running = false;
246                                                 }
247                                         }
248                                 }
249                         });
250                 thread.start();
251         }
252
253         private boolean set_igniter(HashMap <String,Integer> status, String name, String pretty) {
254                 if (!status.containsKey(name))
255                         return false;
256
257                 IgniterItem item;
258                 if (!igniters.containsKey(name)) {
259                         item = new IgniterItem();
260                         igniters.put(name, item);
261                         igniters_adapter.add(item);
262                 } else
263                         item = igniters.get(name);
264
265                 item.set(name, pretty, AltosIgnite.status_string(status.get(name)));
266                 return true;
267         }
268
269         private synchronized void igniter_status(HashMap <String,Integer> status) {
270                 query_timer_running = false;
271                 if (status == null) {
272                         AltosDebug.debug("no igniter status");
273                         return;
274                 }
275                 set_igniter(status, "drogue", "Apogee");
276                 set_igniter(status, "main", "Main");
277                 for (int extra = 0;; extra++) {
278                         String  name = String.format("%d", extra);
279                         String  pretty = String.format("%c", 'A' + extra);
280                         if (!set_igniter(status, name, pretty))
281                                 break;
282                 }
283         }
284
285         private synchronized void arm_timer_stop() {
286                 if (arm_timer != null) {
287                         arm_timer.cancel();
288                         arm_timer = null;
289                 }
290                 arm_remaining = 0;
291         }
292
293         private void arm_set_text() {
294                 String  text = String.format("Armed %d", arm_remaining);
295
296                 if (arm.isChecked())
297                         arm.setText(text);
298                 arm.setTextOn(text);
299         }
300
301         private void arm_timer_tick() {
302                 --arm_remaining;
303                 if (arm_remaining <= 0) {
304                         arm_timer_stop();
305                         runOnUiThread(new Runnable() {
306                                         public void run() {
307                                                 arm.setChecked(false);
308                                                 fire.setEnabled(false);
309                                         }
310                                 });
311                 } else {
312                         runOnUiThread(new Runnable() {
313                                         public void run() {
314                                                 arm_set_text();
315                                         }
316                                 });
317                 }
318         }
319
320         private void select_item(int position) {
321                 if (position != igniters_adapter.selected_item) {
322                         if (igniters_adapter.selected_item >= 0)
323                                 igniters_view.setItemChecked(igniters_adapter.selected_item, false);
324                         if (position >= 0) {
325                                 igniters_view.setItemChecked(position, true);
326                                 arm.setEnabled(true);
327                         } else
328                                 arm.setEnabled(false);
329                         igniters_adapter.selected_item = position;
330                 }
331         }
332
333         private class IgniterItemClickListener implements ListView.OnItemClickListener {
334                 @Override
335                 public void onItemClick(AdapterView<?> av, View v, int position, long id) {
336                         AltosDebug.debug("select %d\n", position);
337                         select_item(position);
338                 }
339         }
340
341         @Override
342         protected void onCreate(Bundle savedInstanceState) {
343                 setTheme(AltosDroid.dialog_themes[AltosDroidPreferences.font_size()]);
344                 super.onCreate(savedInstanceState);
345
346                 // Setup the window
347                 setContentView(R.layout.igniters);
348
349                 igniters_view = (ListView) findViewById(R.id.igniters);
350                 igniters_view.setClickable(true);
351
352                 igniters_adapter = new IgniterAdapter(this, R.layout.igniter_status);
353
354                 igniters_view.setAdapter(igniters_adapter);
355                 igniters_view.setOnItemClickListener(new IgniterItemClickListener());
356
357                 fire = (Button) findViewById(R.id.igniter_fire);
358                 fire.setEnabled(false);
359                 fire.setOnClickListener(new OnClickListener() {
360                                 public void onClick(View v) {
361                                         fire_igniter();
362                                 }
363                         });
364
365                 arm = (ToggleButton) findViewById(R.id.igniter_arm);
366                 arm.setEnabled(false);
367                 arm.setOnCheckedChangeListener(new ToggleButton.OnCheckedChangeListener() {
368                                 public void onCheckedChanged(CompoundButton v, boolean is_checked) {
369                                         arm_igniter(is_checked);
370                                 }
371                         });
372
373                 // Set result CANCELED incase the user backs out
374                 setResult(Activity.RESULT_CANCELED);
375         }
376
377         @Override
378         protected void onStart() {
379                 super.onStart();
380                 doBindService();
381         }
382
383         @Override
384         protected void onResume() {
385                 super.onResume();
386                 query_timer = new Timer(true);
387                 query_timer.scheduleAtFixedRate(new TimerTask() {
388                                 public void run() {
389                                         query_timer_tick();
390                                 }},
391                         0L, 5000L);
392         }
393
394         @Override
395         protected void onPause() {
396                 super.onPause();
397                 if (query_timer != null) {
398                         query_timer.cancel();
399                         query_timer = null;
400                 }
401                 arm_timer_stop();
402                 arm.setChecked(false);
403                 fire.setEnabled(false);
404         }
405
406         @Override
407         protected void onStop() {
408                 super.onStop();
409                 doUnbindService();
410         }
411 }