2 * Copyright © 2016 Keith Packard <keithp@keithp.com>
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.
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.
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.
19 package org.altusmetrum.AltosDroid;
21 import java.lang.ref.WeakReference;
23 import org.altusmetrum.AltosDroid.R;
25 import android.app.Activity;
26 import android.bluetooth.BluetoothAdapter;
27 import android.bluetooth.BluetoothDevice;
28 import android.content.*;
29 import android.graphics.*;
31 import android.view.*;
32 import android.view.View.*;
33 import android.widget.*;
34 import android.widget.AdapterView.*;
36 import org.altusmetrum.altoslib_11.*;
42 public LinearLayout igniter_view = null;
43 public TextView pretty_view = null;
44 public TextView status_view = null;
46 private void update() {
47 if (pretty_view != null)
48 pretty_view.setText(pretty);
49 if (status_view != null)
50 status_view.setText(status);
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))
65 public void realize(LinearLayout igniter_view,
67 TextView status_view) {
68 if (igniter_view != this.igniter_view ||
69 pretty_view != this.pretty_view ||
70 status_view != this.status_view)
72 this.igniter_view = igniter_view;
73 this.pretty_view = pretty_view;
74 this.status_view = status_view;
79 public IgniterItem() {
83 class IgniterAdapter extends ArrayAdapter<IgniterItem> {
85 int selected_item = -1;
87 public IgniterAdapter(Context context, int in_resource) {
88 super(context, in_resource);
89 resource = in_resource;
93 public View getView(int position, View convertView, ViewGroup parent) {
94 IgniterItem item = getItem(position);
95 if (item.igniter_view == null) {
96 LinearLayout igniter_view = new LinearLayout(getContext());
97 String inflater = Context.LAYOUT_INFLATER_SERVICE;
98 LayoutInflater li = (LayoutInflater) getContext().getSystemService(inflater);
99 li.inflate(resource, igniter_view, true);
101 item.realize(igniter_view,
102 (TextView) igniter_view.findViewById(R.id.igniter_name),
103 (TextView) igniter_view.findViewById(R.id.igniter_status));
105 if (position == selected_item)
106 item.igniter_view.setBackgroundColor(Color.RED);
108 item.igniter_view.setBackgroundColor(Color.BLACK);
109 return item.igniter_view;
113 public class IgniterActivity extends Activity {
114 private ListView igniters_view;
115 private ToggleButton arm;
118 private HashMap<String,IgniterItem> igniters = new HashMap<String,IgniterItem>();;
120 private IgniterAdapter igniters_adapter;
122 private boolean is_bound;
123 private Messenger service = null;
124 private final Messenger messenger = new Messenger(new IncomingHandler(this));
126 private Timer query_timer;
127 private boolean query_timer_running;
129 private Timer arm_timer;
130 private int arm_remaining;
132 public static final int IGNITER_QUERY = 1;
133 public static final int IGNITER_FIRE = 2;
135 // The Handler that gets information back from the Telemetry Service
136 static class IncomingHandler extends Handler {
137 private final WeakReference<IgniterActivity> igniter_activity;
138 IncomingHandler(IgniterActivity ia) { igniter_activity = new WeakReference<IgniterActivity>(ia); }
141 public void handleMessage(Message msg) {
142 IgniterActivity ia = igniter_activity.get();
145 case AltosDroid.MSG_IGNITER_STATUS:
146 ia.igniter_status((HashMap <String,Integer>) msg.obj);
153 private ServiceConnection connection = new ServiceConnection() {
154 public void onServiceConnected(ComponentName className, IBinder binder) {
155 service = new Messenger(binder);
159 public void onServiceDisconnected(ComponentName className) {
160 // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
165 void doBindService() {
166 bindService(new Intent(this, TelemetryService.class), connection, Context.BIND_AUTO_CREATE);
170 void doUnbindService() {
172 // If we have received the service, and hence registered with it, then now is the time to unregister.
173 unbindService(connection);
178 private void done() {
179 Intent intent = new Intent();
180 setResult(Activity.RESULT_OK, intent);
184 class FireThread extends Thread {
185 private final String igniter;
189 Message msg = Message.obtain(null, TelemetryService.MSG_IGNITER_FIRE, igniter);
192 } catch (RemoteException re) {
196 public FireThread(String igniter) {
197 this.igniter = igniter;
201 private void fire_igniter() {
202 if (igniters_adapter.selected_item >= 0) {
203 IgniterItem item = igniters_adapter.getItem(igniters_adapter.selected_item);
204 FireThread ft = new FireThread(item.name);
206 arm.setChecked(false);
210 private void arm_igniter(boolean is_checked) {
213 arm_timer = new Timer();
216 fire.setEnabled(true);
217 arm_timer.scheduleAtFixedRate(new TimerTask() {
224 fire.setEnabled(false);
228 private synchronized void query_timer_tick() {
229 if (query_timer_running)
233 query_timer_running = true;
234 Thread thread = new Thread(new Runnable() {
237 Message msg = Message.obtain(null, TelemetryService.MSG_IGNITER_QUERY);
238 msg.replyTo = messenger;
239 if (service == null) {
240 synchronized(IgniterActivity.this) {
241 query_timer_running = false;
245 } catch (RemoteException re) {
246 AltosDebug.debug("igniter query thread failed");
247 synchronized(IgniterActivity.this) {
248 query_timer_running = false;
256 private boolean set_igniter(HashMap <String,Integer> status, String name, String pretty) {
257 if (!status.containsKey(name))
261 if (!igniters.containsKey(name)) {
262 item = new IgniterItem();
263 igniters.put(name, item);
264 igniters_adapter.add(item);
266 item = igniters.get(name);
268 item.set(name, pretty, AltosIgnite.status_string(status.get(name)));
272 private synchronized void igniter_status(HashMap <String,Integer> status) {
273 query_timer_running = false;
274 if (status == null) {
275 AltosDebug.debug("no igniter status");
278 set_igniter(status, "drogue", "Apogee");
279 set_igniter(status, "main", "Main");
280 for (int extra = 0;; extra++) {
281 String name = String.format("%d", extra);
282 String pretty = String.format("%c", 'A' + extra);
283 if (!set_igniter(status, name, pretty))
288 private synchronized void arm_timer_stop() {
289 if (arm_timer != null) {
296 private void arm_set_text() {
297 String text = String.format("Armed %d", arm_remaining);
304 private void arm_timer_tick() {
306 if (arm_remaining <= 0) {
308 runOnUiThread(new Runnable() {
310 arm.setChecked(false);
311 fire.setEnabled(false);
315 runOnUiThread(new Runnable() {
323 private void select_item(int position) {
324 if (position != igniters_adapter.selected_item) {
325 if (igniters_adapter.selected_item >= 0)
326 igniters_view.setItemChecked(igniters_adapter.selected_item, false);
328 igniters_view.setItemChecked(position, true);
329 arm.setEnabled(true);
331 arm.setEnabled(false);
332 igniters_adapter.selected_item = position;
336 private class IgniterItemClickListener implements ListView.OnItemClickListener {
338 public void onItemClick(AdapterView<?> av, View v, int position, long id) {
339 AltosDebug.debug("select %d\n", position);
340 select_item(position);
345 protected void onCreate(Bundle savedInstanceState) {
346 super.onCreate(savedInstanceState);
349 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
350 setContentView(R.layout.igniters);
352 igniters_view = (ListView) findViewById(R.id.igniters);
353 igniters_view.setClickable(true);
355 igniters_adapter = new IgniterAdapter(this, R.layout.igniter_status);
357 igniters_view.setAdapter(igniters_adapter);
358 igniters_view.setOnItemClickListener(new IgniterItemClickListener());
360 fire = (Button) findViewById(R.id.igniter_fire);
361 fire.setEnabled(false);
362 fire.setOnClickListener(new OnClickListener() {
363 public void onClick(View v) {
368 arm = (ToggleButton) findViewById(R.id.igniter_arm);
369 arm.setEnabled(false);
370 arm.setOnCheckedChangeListener(new ToggleButton.OnCheckedChangeListener() {
371 public void onCheckedChanged(CompoundButton v, boolean is_checked) {
372 arm_igniter(is_checked);
376 // Set result CANCELED incase the user backs out
377 setResult(Activity.RESULT_CANCELED);
381 protected void onStart() {
387 protected void onResume() {
389 query_timer = new Timer(true);
390 query_timer.scheduleAtFixedRate(new TimerTask() {
398 protected void onPause() {
400 if (query_timer != null) {
401 query_timer.cancel();
405 arm.setChecked(false);
406 fire.setEnabled(false);
410 protected void onStop() {