a608bba0e91a46a8cc4da110743e374e320c9140
[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 status;
40         public LinearLayout igniter_view = null;
41         public TextView name_view = null;
42         public TextView status_view = null;
43
44         private void update() {
45                 AltosDebug.debug("update item %s %s", name, status);
46                 if (name_view != null)
47                         name_view.setText(name);
48                 if (status_view != null)
49                         status_view.setText(status);
50         }
51
52         public void set(String name, String status) {
53                 if (!name.equals(this.name) || !status.equals(this.status)) {
54                         this.name = name;
55                         this.status = status;
56                         update();
57                 }
58         }
59
60         public void realize(LinearLayout igniter_view,
61                             TextView name_view,
62                             TextView status_view) {
63                 if (igniter_view != this.igniter_view ||
64                     name_view != this.name_view ||
65                     status_view != this.status_view)
66                 {
67                         this.igniter_view = igniter_view;
68                         this.name_view = name_view;
69                         this.status_view = status_view;
70                         update();
71                 }
72         }
73
74         public IgniterItem() {
75                 AltosDebug.debug("New igniter item");
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                         AltosDebug.debug("Realize new igniter view");
101                 } else
102                         AltosDebug.debug("Reuse existing igniter view");
103                 if (position == selected_item)
104                         item.igniter_view.setBackgroundColor(Color.RED);
105                 else
106                         item.igniter_view.setBackgroundColor(Color.BLACK);
107                 return item.igniter_view;
108         }
109 }
110
111 public class IgniterActivity extends Activity {
112         private ListView igniters_view;
113         private ToggleButton arm;
114         private Button fire;
115
116         private HashMap<String,IgniterItem> igniters = new HashMap<String,IgniterItem>();;
117
118         private IgniterAdapter igniters_adapter;
119
120         private boolean is_bound;
121         private boolean timer_running;
122         private Messenger service = null;
123         private final Messenger messenger = new Messenger(new IncomingHandler(this));
124
125         private Timer timer;
126
127         public static final int IGNITER_QUERY = 1;
128         public static final int IGNITER_FIRE = 2;
129
130         // The Handler that gets information back from the Telemetry Service
131         static class IncomingHandler extends Handler {
132                 private final WeakReference<IgniterActivity> igniter_activity;
133                 IncomingHandler(IgniterActivity ia) { igniter_activity = new WeakReference<IgniterActivity>(ia); }
134
135                 @Override
136                 public void handleMessage(Message msg) {
137                         IgniterActivity ia = igniter_activity.get();
138
139                         switch (msg.what) {
140                         case AltosDroid.MSG_IGNITER_STATUS:
141                                 ia.igniter_status((HashMap <String,Integer>) msg.obj);
142                                 break;
143                         }
144                 }
145         };
146
147
148         private ServiceConnection connection = new ServiceConnection() {
149                 public void onServiceConnected(ComponentName className, IBinder binder) {
150                         service = new Messenger(binder);
151                 }
152
153                 public void onServiceDisconnected(ComponentName className) {
154                         // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
155                         service = null;
156                 }
157         };
158
159         void doBindService() {
160                 bindService(new Intent(this, TelemetryService.class), connection, Context.BIND_AUTO_CREATE);
161                 is_bound = true;
162         }
163
164         void doUnbindService() {
165                 if (is_bound) {
166                         // If we have received the service, and hence registered with it, then now is the time to unregister.
167                         unbindService(connection);
168                         is_bound = false;
169                 }
170         }
171
172         private void done() {
173                 Intent intent = new Intent();
174                 setResult(Activity.RESULT_OK, intent);
175                 finish();
176         }
177
178         private void fire_igniter() {
179         }
180
181         private void arm_igniter(boolean is_checked) {
182         }
183
184         private synchronized void timer_tick() {
185                 if (timer_running)
186                         return;
187                 timer_running = true;
188                 try {
189                         Message msg = Message.obtain(null, TelemetryService.MSG_IGNITER_QUERY);
190                         msg.replyTo = messenger;
191                         service.send(msg);
192                 } catch (RemoteException re) {
193                 }
194         }
195
196         private boolean set_igniter(HashMap <String,Integer> status, String name, String pretty) {
197                 if (!status.containsKey(name))
198                         return false;
199
200                 IgniterItem item;
201                 if (!igniters.containsKey(name)) {
202                         item = new IgniterItem();
203                         igniters.put(name, item);
204                         igniters_adapter.add(item);
205                 } else
206                         item = igniters.get(name);
207
208                 item.set(pretty, AltosIgnite.status_string(status.get(name)));
209                 return true;
210         }
211
212         private synchronized void igniter_status(HashMap <String,Integer> status) {
213                 timer_running = false;
214                 if (status == null) {
215                         AltosDebug.debug("no igniter status");
216                         return;
217                 }
218                 set_igniter(status, "drogue", "Apogee");
219                 set_igniter(status, "main", "Main");
220                 for (int extra = 0;; extra++) {
221                         String  name = String.format("%d", extra);
222                         String  pretty = String.format("%c", 'A' + extra);
223                         if (!set_igniter(status, name, pretty))
224                                 break;
225                 }
226 //              if (igniters_adapter.selected_item >= 0)
227 //                      igniters_view.setSelection(selected_item);
228         }
229
230         private class IgniterItemClickListener implements ListView.OnItemClickListener {
231                 @Override
232                 public void onItemClick(AdapterView<?> av, View v, int position, long id) {
233                         if (igniters_adapter.selected_item >= 0)
234                                 igniters_view.setItemChecked(igniters_adapter.selected_item, false);
235                         igniters_view.setItemChecked(position, true);
236                         igniters_adapter.selected_item = position;
237                 }
238         }
239
240         @Override
241         protected void onCreate(Bundle savedInstanceState) {
242                 super.onCreate(savedInstanceState);
243
244                 // Setup the window
245                 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
246                 setContentView(R.layout.igniters);
247
248                 igniters_view = (ListView) findViewById(R.id.igniters);
249                 igniters_view.setClickable(true);
250
251                 igniters_adapter = new IgniterAdapter(this, R.layout.igniter_status);
252
253                 igniters_view.setAdapter(igniters_adapter);
254                 igniters_view.setOnItemClickListener(new IgniterItemClickListener());
255
256                 fire = (Button) findViewById(R.id.igniter_fire);
257                 fire.setOnClickListener(new OnClickListener() {
258                                 public void onClick(View v) {
259                                         fire_igniter();
260                                 }
261                         });
262
263                 arm = (ToggleButton) findViewById(R.id.igniter_arm);
264                 arm.setOnCheckedChangeListener(new ToggleButton.OnCheckedChangeListener() {
265                                 public void onCheckedChanged(CompoundButton v, boolean is_checked) {
266                                         arm_igniter(is_checked);
267                                 }
268                         });
269
270                 // Set result CANCELED incase the user backs out
271                 setResult(Activity.RESULT_CANCELED);
272         }
273
274         @Override
275         protected void onStart() {
276                 super.onStart();
277                 doBindService();
278         }
279
280         @Override
281         protected void onResume() {
282                 super.onResume();
283                 timer = new Timer(true);
284                 timer.scheduleAtFixedRate(new TimerTask() {
285                                 public void run() {
286                                         timer_tick();
287                                 }},
288                         1000L, 1000L);
289         }
290
291         @Override
292         protected void onPause() {
293                 super.onPause();
294                 timer.cancel();
295                 timer = null;
296         }
297
298         @Override
299         protected void onStop() {
300                 super.onStop();
301                 doUnbindService();
302         }
303 }