1 package com.example.lede2;
\r
3 import android.app.ActivityManager;
\r
4 import android.app.ProgressDialog;
\r
5 import android.content.Context;
\r
6 import android.os.AsyncTask;
\r
7 import android.os.Bundle;
\r
8 import android.os.Handler;
\r
9 import android.support.design.widget.Snackbar;
\r
10 import android.support.v7.app.AppCompatActivity;
\r
11 import android.util.Log;
\r
12 import android.util.Pair;
\r
13 import android.view.View;
\r
14 import android.view.WindowManager;
\r
15 import android.view.inputmethod.InputMethodManager;
\r
16 import android.widget.AdapterView;
\r
17 import android.widget.ArrayAdapter;
\r
18 import android.widget.Button;
\r
19 import android.widget.EditText;
\r
20 import android.widget.ProgressBar;
\r
21 import android.widget.Spinner;
\r
22 import android.widget.TextView;
\r
23 import android.widget.Toast;
\r
25 import java.io.File;
\r
26 import java.nio.file.FileAlreadyExistsException;
\r
27 import java.text.CollationElementIterator;
\r
28 import java.util.ArrayList;
\r
29 import java.util.Collections;
\r
30 import java.util.HashMap;
\r
31 import java.util.List;
\r
32 import java.util.Set;
\r
35 public class AddDeviceActivity extends AppCompatActivity implements View.OnClickListener,View.OnFocusChangeListener {
\r
37 DatabaseObject databaseObject;
\r
38 //DatabaseSubtypeObject databaseSubtypeObject;
\r
40 EditText databaseInfo;
\r
45 ProgressBar progressBar;
\r
46 private ArrayAdapter subtypeAdapter;
\r
47 private ArrayAdapter paramAdapter;
\r
48 private ArrayAdapter fieldAdapter;
\r
49 String lastParamChosen;
\r
50 TextView databaseAddressInfo;
\r
51 protected String database_information_filename;
\r
52 protected String id_information_filename;
\r
54 HashMap<String, String> userInputs;
\r
55 ProgressDialog dialog;
\r
58 private SSH_MySQL ssh;//Connection object between Android & Host
\r
61 protected void onCreate(Bundle savedInstanceState) {
\r
62 super.onCreate(savedInstanceState);
\r
63 setContentView(R.layout.activity_add_device);
\r
66 doneButton = (Button) findViewById(R.id.doneButton);
\r
67 spinner1 = (Spinner) findViewById(R.id.spinner1);
\r
68 spinner2 = (Spinner) findViewById(R.id.spinner2);
\r
69 spinner3 = (Spinner) findViewById(R.id.spinner3);
\r
70 spinner4 = (Spinner) findViewById(R.id.spinner4);
\r
71 databaseInfo = (EditText)findViewById(R.id.textInfo);
\r
72 progressBar = (ProgressBar)findViewById(R.id.progressBar);
\r
73 progressBar.setVisibility(View.INVISIBLE);
\r
74 progressBar.setMax(10);
\r
75 //databaseAddressInfo = (EditText)findViewById(R.id.textInfoAddress);
\r
76 database_information_filename = this.getString(R.string.device_param_config_filename);
\r
77 id_information_filename = this.getString(R.string.device_id_config_filename);
\r
78 userInputs = new HashMap<String, String>();
\r
80 lastParamChosen = "";
\r
82 //looks through database to see possible subtypes for dropdown box 2
\r
83 spinner1.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
\r
84 //set spinner2 values = subtypes of type chosen for spinner 1
\r
86 public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
\r
88 String selectedType = spinner1.getSelectedItem().toString();
\r
89 Set<String> keysForSubType = (databaseObject.getTypeObject(selectedType)).getKeySet();
\r
90 ArrayList<String> subtypes = new ArrayList<String>();
\r
91 for(String key: keysForSubType){
\r
94 Collections.sort(subtypes);
\r
95 subtypeAdapter = new ArrayAdapter(context, android.R.layout.simple_spinner_dropdown_item, subtypes);
\r
96 subtypeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
\r
97 spinner2.setAdapter(subtypeAdapter);
\r
102 public void onNothingSelected(AdapterView<?> adapterView) {
\r
106 spinner2.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
\r
107 //set spinner 3 values based on if the selected subtype has params and/or addressparams
\r
109 public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
\r
110 DatabaseSubtypeObject subtypeObject = getCurrentSubtypeObject();
\r
112 ArrayList<String> paramType = new ArrayList<String>();
\r
113 if(subtypeObject.getParams().size() > 0){
\r
114 paramType.add("Device");
\r
116 if(subtypeObject.getAddressParams().size() > 0){
\r
117 paramType.add("Address");
\r
119 if(subtypeObject.getZigbeeAddressParams().size()>0){
\r
120 paramType.add("Zigbee");
\r
122 //if both empty(example room)
\r
123 if(subtypeObject.getAddressParams().size() == 0 && subtypeObject.getParams().size() == 0){
\r
124 paramType.add("No Device or Address Parameters");
\r
126 Collections.sort(paramType);
\r
127 paramAdapter = new ArrayAdapter(context, android.R.layout.simple_spinner_dropdown_item, paramType);
\r
128 spinner3.setAdapter(paramAdapter);
\r
132 public void onNothingSelected(AdapterView<?> adapterView) {
\r
136 spinner3.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
\r
137 //set spinner 4 value based on spinner1-3 values (actual params)
\r
139 public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
\r
140 DatabaseSubtypeObject subtypeObject = getCurrentSubtypeObject();
\r
141 List<String> keysForSubType = new ArrayList<>();
\r
142 //for devices that have no fields ex Rooms
\r
143 if(spinner3.getSelectedItem().toString().equals("No Device or Address Parameters")) {
\r
144 keysForSubType.add("No Fields");
\r
146 databaseInfo.setVisibility(View.GONE);
\r
148 if(spinner3.getSelectedItem().toString().equals("Device")) {
\r
149 databaseInfo.setVisibility(View.VISIBLE);
\r
150 if(subtypeObject.getNumParams() > 0){
\r
151 //add only params that have USER value
\r
152 ArrayList<Pair<String, String>> tempList = subtypeObject.getParams();
\r
153 for(int j = 0; j < tempList.size(); j++){
\r
154 if(tempList.get(j).second.equals("USER")){
\r
155 keysForSubType.add(tempList.get(j).first);
\r
161 else if(spinner3.getSelectedItem().toString().equals("Zigbee")){
\r
162 //setting field name for zigbee
\r
163 databaseInfo.setVisibility(View.VISIBLE);
\r
164 keysForSubType.add("DEVICEADDRESS");
\r
167 //if selected value is address
\r
168 if(subtypeObject.getNumAddressParams() > 0){
\r
169 databaseInfo.setVisibility(View.VISIBLE);
\r
170 //add only params that have USER value
\r
171 ArrayList<ArrayList<Pair<String, String>>> tempList = subtypeObject.getAddressParams();
\r
172 for(int j = 0; j < tempList.size(); j++){
\r
173 for(int k = 0; k < tempList.get(j).size(); k++){
\r
174 if(tempList.get(j).get(k).second.equals("USER")){
\r
175 if(!keysForSubType.contains(tempList.get(j).get(k).first)) {
\r
176 keysForSubType.add(tempList.get(j).get(k).first);
\r
185 //List<String> keysForSubType = (databaseObject.getTypeObject(selectedType)).getSubtypeObject(selectedSubtype).getParams();
\r
187 ArrayList<String> params = new ArrayList<String>();
\r
188 for(String key: keysForSubType){
\r
191 Collections.sort(params);
\r
192 fieldAdapter = new ArrayAdapter(context, android.R.layout.simple_spinner_dropdown_item, params);
\r
193 fieldAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
\r
194 spinner4.setAdapter(fieldAdapter);
\r
198 public void onNothingSelected(AdapterView<?> adapterView) {
\r
202 spinner4.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
\r
203 //saves user input into a hashmap that is used later to create ssh command
\r
205 public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
\r
207 if(!spinner3.getSelectedItem().toString().equals("No Device or Address Parameters")) {
\r
208 if (lastParamChosen.equals("")) {
\r
209 lastParamChosen = spinner2.getSelectedItem().toString() + spinner3.getSelectedItem().toString() + spinner4.getSelectedItem().toString();
\r
212 String enteredText = databaseInfo.getText().toString();
\r
213 userInputs.put(lastParamChosen, enteredText);
\r
214 String currentSelections = spinner2.getSelectedItem().toString() + spinner3.getSelectedItem().toString() + spinner4.getSelectedItem().toString();
\r
215 if (!userInputs.containsKey(currentSelections)) {
\r
216 userInputs.put(currentSelections, "");
\r
218 databaseInfo.setText(userInputs.get(currentSelections));
\r
219 lastParamChosen = currentSelections;
\r
227 public void onNothingSelected(AdapterView<?> adapterView) {
\r
231 doneButton.setOnClickListener(this);
\r
232 // Set config text from file for device
\r
233 //pull information from config file and uses it to generate main database object
\r
235 String idInformation = ConfigFileIO.readFromFile(id_information_filename, this);
\r
236 databaseObject = ConfigFileIO.createDatabaseObject(this, idInformation );
\r
240 //ConfigFileIO.printDatabaseObject(databaseObject);
\r
241 Set<String> keysForType = databaseObject.getKeySet();
\r
242 ArrayList<String> types = new ArrayList<String>();
\r
243 for(String key: keysForType){
\r
246 //sets value for spinner 1
\r
247 Collections.sort(types);
\r
248 ArrayAdapter typeAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, types);
\r
249 typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
\r
250 spinner1.setAdapter(typeAdapter);
\r
256 public void onClick(View v) {
\r
257 if(v == doneButton){
\r
258 String enteredText = databaseInfo.getText().toString();
\r
259 //combines user input into a command for the pi
\r
260 String keyForUserInput = spinner2.getSelectedItem().toString() + spinner3.getSelectedItem().toString() + spinner4.getSelectedItem().toString();
\r
261 userInputs.put(keyForUserInput, enteredText);
\r
262 if(!sufficientEntries()) {
\r
263 Snackbar done = Snackbar.make(findViewById(R.id.done),
\r
264 "Please Enter all required fields for selected device type", 2000);
\r
268 Snackbar done = Snackbar.make(findViewById(R.id.done), "Updating IoTDeviceAddress.config", 2000);
\r
270 progressBar.setVisibility(View.VISIBLE);
\r
271 doneButton.setAlpha(.5f);
\r
272 doneButton.setClickable(false);
\r
278 String sqlCommand = generateSQLCommand();
\r
279 System.out.println(sqlCommand);
\r
280 Log.d("sqlcommand", sqlCommand);
\r
281 System.out.println("");
\r
283 ssh = new SSH_MySQL();
\r
284 ssh.execute(sqlCommand);
\r
286 Thread.sleep(1000);
\r
287 List<String> result = ssh.getResultLines();
\r
288 for (int i = 0; i < result.size(); i++) {
\r
289 System.out.println("result" + result.get(i));
\r
291 } catch (Exception e) {
\r
292 e.printStackTrace();
\r
296 updateIoTDeviceAddress();
\r
297 // done = Snackbar.make(findViewById(R.id.done),
\r
298 // "Updating SetList.config", 2000);
\r
305 //determines if all fields have been entered
\r
306 public boolean sufficientEntries(){
\r
307 boolean sufficient = true;
\r
308 DatabaseSubtypeObject subtypeObject = getCurrentSubtypeObject();
\r
309 ArrayList<Pair<String, String>> params = subtypeObject.getParams();
\r
310 ArrayList<ArrayList<Pair<String, String>>> addressParams = subtypeObject.getAddressParams();
\r
311 ArrayList<ArrayList<Pair<String, String>>> zigbeeAddressParams = subtypeObject.getZigbeeAddressParams();
\r
312 if(spinner3.getSelectedItem().toString().equals("No Device or Address Parameters")) {
\r
315 if(params.size()>0){
\r
316 for(int i = 0; i < params.size(); i++){
\r
317 if(!params.get(i).second.equals("USER")){
\r
320 if(!userInputs.containsKey(spinner2.getSelectedItem().toString() + "Device" + params.get(i).first) ||
\r
321 userInputs.get(spinner2.getSelectedItem().toString() + "Device" + params.get(i).first).equals("")){
\r
322 sufficient = false;
\r
326 if(addressParams.size()>0){
\r
327 for(int i = 0; i < addressParams.size(); i++){
\r
328 for(int j = 0;j < addressParams.get(i).size(); j++) {
\r
329 if(!addressParams.get(i).get(j).second.equals("USER")){
\r
332 if (!userInputs.containsKey(spinner2.getSelectedItem().toString() + "Address" + addressParams.get(i).get(j).first) ||
\r
333 userInputs.get(spinner2.getSelectedItem().toString() + "Address" + addressParams.get(i).get(j).first).equals("")) {
\r
334 sufficient = false;
\r
339 if(zigbeeAddressParams.size()>0){
\r
340 for(int i = 0; i < zigbeeAddressParams.size(); i++){
\r
341 for(int j = 0;j < zigbeeAddressParams.get(i).size(); j++) {
\r
342 if(!zigbeeAddressParams.get(i).get(j).second.equals("USER")){
\r
345 if (!userInputs.containsKey(spinner2.getSelectedItem().toString() + "Zigbee" + zigbeeAddressParams.get(i).get(j).first) ||
\r
346 userInputs.get(spinner2.getSelectedItem().toString() + "Zigbee" + zigbeeAddressParams.get(i).get(j).first).equals("")) {
\r
347 sufficient = false;
\r
357 public void onFocusChange(View view, boolean hasFocus) {
\r
358 InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
\r
360 imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
\r
362 imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
\r
365 //generates command for adding both device and address device. May need to expand for zigbee
\r
366 public String generateSQLCommand(){
\r
367 String command = "";
\r
368 String paramInfo = "";
\r
369 String addressParamInfo = "";
\r
370 DatabaseSubtypeObject subtypeObject = getCurrentSubtypeObject();
\r
371 int numAddresses = subtypeObject.getNumAddresses();
\r
372 int numZigbeeAddresses = subtypeObject.getNumZigbeeAddresses();
\r
373 // 1) Create a new file and insert the configuration
\r
374 // 2) Run iotinstaller code for device installation
\r
375 // 3) Remove the existing config file
\r
376 // 4) Repeat 1, 2, and 3 for device address
\r
377 command += "echo \"" + generateDevFields() + "\" >> " +
\r
378 MainActivity.DEF_MYSQL_CONFIG_FILE + ";" +
\r
379 MainActivity.DEF_INSTALL_CMD + " " + MainActivity.DEF_MYSQL_CONFIG_FILE + ";" +
\r
380 "rm -rf " + MainActivity.DEF_MYSQL_CONFIG_FILE + ";";
\r
381 // repeat process for device address
\r
382 for(int i = 0; i <numAddresses; i++ ) {
\r
383 boolean multiple = true;
\r
384 if(numAddresses == 1){
\r
387 command += "echo \"" + generateAddressFields(i, multiple) + "\" >> " +
\r
388 MainActivity.DEF_MYSQL_CONFIG_FILE + ";" +
\r
389 MainActivity.DEF_INSTALL_ADDRESS_CMD + " " + MainActivity.DEF_MYSQL_CONFIG_FILE + ";"
\r
390 + "rm -rf " + MainActivity.DEF_MYSQL_CONFIG_FILE + ";";
\r
392 for(int i = 0; i < numZigbeeAddresses; i++){
\r
393 boolean multiple = true;
\r
394 if(numZigbeeAddresses == 1){
\r
397 command += "echo \"" + generateZigBeeAddressFields(i, multiple) + "\" >> " +
\r
398 MainActivity.DEF_MYSQL_CONFIG_FILE + ";" +
\r
399 MainActivity.DEF_INSTALL_ZBADDRESS_CMD + " " + MainActivity.DEF_MYSQL_CONFIG_FILE + ";"
\r
400 + "rm -rf " + MainActivity.DEF_MYSQL_CONFIG_FILE + ";";
\r
406 //specific device information to be inserted into the sql command. follows format seen in config file on pi
\r
407 public String generateDevFields(){
\r
408 String fields = "";
\r
409 DatabaseSubtypeObject subtypeObject = getCurrentSubtypeObject();
\r
411 fields += context.getResources().getString(R.string.database_name) + "\n"
\r
412 + "ID " + subtypeObject.getNextID() + "\n"
\r
413 + "TYPE " + spinner1.getSelectedItem().toString()+ "\n"
\r
414 + "TYPESPECIFIC " + spinner2.getSelectedItem().toString()+ "\n"
\r
416 //This sets up the param types and size. special case for devices with no params
\r
417 if(subtypeObject.getNumParams() == 0){
\r
418 fields += "Table 1" + "\n"
\r
419 + "EMPTY VARCHAR 0 " + "\n";
\r
422 //Case for when there are params
\r
424 fields += "Table " + subtypeObject.getNumParams() + "\n";
\r
426 ArrayList<Pair<String,String>> params = subtypeObject.getParams();
\r
427 for(int i = params.size()-1; i >= 0; i--){
\r
428 fields += params.get(i).first + " VARCHAR 20 \n";
\r
430 fields += "END\n\n";
\r
432 fields += "Data \n";
\r
433 for(int i = params.size()-1; i >= 0; i--){
\r
434 fields += userInputs.get(spinner2.getSelectedItem().toString() +
\r
436 params.get(i).first) + "\n";
\r
438 fields += "END\n\n";
\r
443 //refactor with string builder but works for now
\r
444 public String generateAddressFields(int i, boolean multiple){
\r
445 String fields = "";
\r
446 String addressNumber = "";
\r
448 addressNumber = Integer.toString(i+1);
\r
450 DatabaseSubtypeObject subtypeObject = getCurrentSubtypeObject();
\r
451 fields += "ID=" + subtypeObject.getNextID() + "\n" ;
\r
452 fields += "ADDRESSFOR=" + subtypeObject.getName()+ "Add"+ addressNumber + "\n" ;
\r
453 ArrayList<ArrayList<Pair<String,String>>> addressParams = subtypeObject.getAddressParams();
\r
454 String currentAddressParam = "";
\r
455 for(int j = 0; j <addressParams.get(i).size(); j++) {
\r
456 //if the value for current address parameter is user, use the input values
\r
457 if(addressParams.get(i).get(j).second.equals("USER")){
\r
458 currentAddressParam = addressParams.get(i).get(j).first;
\r
459 fields += currentAddressParam + "=" + userInputs.get(spinner2.getSelectedItem().toString() + "Address" + currentAddressParam) + "\n";
\r
461 //if the value for the current address is not user, use the predefined values
\r
463 currentAddressParam = addressParams.get(i).get(j).first;
\r
464 fields += currentAddressParam + "=" + addressParams.get(i).get(j).second + "\n";
\r
467 fields += "END\n\n";
\r
470 public String generateZigBeeAddressFields(int i , boolean multiple){
\r
471 String fields = "";
\r
472 String addressNumber = "";
\r
474 addressNumber = Integer.toString(i+1);
\r
476 DatabaseSubtypeObject subtypeObject = getCurrentSubtypeObject();
\r
477 fields += "ID=" + subtypeObject.getNextID() + "\n" ;
\r
478 fields += "ADDRESSFOR=" + subtypeObject.getName()+ "ZBAdd"+ addressNumber + "\n" ;
\r
479 ArrayList<ArrayList<Pair<String,String>>> zigbeeAddressParams = subtypeObject.getZigbeeAddressParams();
\r
480 String currentAddressParam = "";
\r
481 for(int j = 0; j < zigbeeAddressParams.get(i).size(); j++) {
\r
482 //if the value for current address parameter is user, use the input values
\r
483 if(zigbeeAddressParams.get(i).get(j).second.equals("USER")){
\r
484 currentAddressParam = zigbeeAddressParams.get(i).get(j).first;
\r
485 fields += currentAddressParam + "=" + userInputs.get(spinner2.getSelectedItem().toString() + "Zigbee" + currentAddressParam) + "\n";
\r
487 //if the value for the current address is not user, use the predefined values
\r
489 currentAddressParam = zigbeeAddressParams.get(i).get(j).first;
\r
490 fields += currentAddressParam + "=" + zigbeeAddressParams.get(i).get(j).second + "\n";
\r
493 fields += "END\n\n";
\r
497 //update local database object and local database config file
\r
498 public void updateDatabase(){
\r
499 DatabaseSubtypeObject subtypeObject = getCurrentSubtypeObject();
\r
500 String deviceID = subtypeObject.getName() + " " + subtypeObject.getNextID() + "\n";
\r
501 ConfigFileIO.writeToFile(id_information_filename, deviceID, this);
\r
502 subtypeObject.insertID();
\r
504 private void updateSetList(){
\r
505 SSH_MySQL ssh = new SSH_MySQL();
\r
506 String command = this.getString(R.string.updateSetList);
\r
507 List<String> results = new ArrayList<>();
\r
508 String setListFilename = this.getString(R.string.setListFilename);
\r
510 ssh.execute(command);
\r
511 Thread.sleep(1000);//To execute asyntask in ssh object, we have to sleep main thread
\r
512 results = ssh.getResultLines();
\r
513 while(results.size() == 0){
\r
515 results = ssh.getResultLines();
\r
517 System.out.println(results);
\r
518 } catch (Exception e) {
\r
519 Log.d("Sleep exception", "exception at getSetsAndRelations");
\r
522 private void updateIoTDeviceAddress(){
\r
523 SSH_MySQL ssh = new SSH_MySQL();
\r
524 String command = this.getString(R.string.updateIoTDeviceAddress);
\r
525 List<String> results = new ArrayList<>();
\r
526 String iotDeviceAddressFilename = this.getString(R.string.updateIoTDeviceAddress);
\r
528 ssh.execute(command);
\r
529 Thread.sleep(1000);//To execute asyntask in ssh object, we have to sleep main thread
\r
530 results = ssh.getResultLines();
\r
531 while(results.size() == 0){
\r
533 results = ssh.getResultLines();
\r
535 System.out.println(results);
\r
536 } catch (Exception e) {
\r
537 Log.d("Sleep exception", "exception at getSetsAndRelations");
\r
542 protected void addSSHResultsToConfig(List<String> results, String filename) {
\r
543 ConfigFileIO.writeToNewFile(filename,"", this );
\r
544 File dir = getFilesDir();
\r
545 File file = new File(dir, filename);
\r
547 for (int i = 0; i < results.size(); i++) {
\r
548 ConfigFileIO.writeToFile(filename, results.get(i), this);
\r
553 public DatabaseSubtypeObject getCurrentSubtypeObject(){
\r
554 return databaseObject.getTypeObject(spinner1.
\r
555 getSelectedItem().toString()).getSubtypeObject(spinner2.getSelectedItem().toString());
\r
559 public class Progress extends AsyncTask<Void, Integer, Void> {
\r
564 protected void onPreExecute() {
\r
565 super.onPreExecute();
\r
567 Log.d("progress", "after dialog.show");
\r
571 protected Void doInBackground(Void... voids) {
\r
572 for(int i = 0; i < 10; i++){
\r
575 publishProgress(i);
\r
576 } catch (InterruptedException e) {
\r
577 e.printStackTrace();
\r
585 protected void onPostExecute(Void aVoid) {
\r
586 super.onPostExecute(aVoid);
\r
591 protected void onProgressUpdate(Integer... values) {
\r
592 super.onProgressUpdate(values);
\r
593 progressBar.setProgress(values[0]);
\r
599 public void finished(){
\r