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