package ie.hennisoft.zumocontrol; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.content.Intent; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.widget.CompoundButton; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import java.io.IOException; import java.io.OutputStream; import java.util.UUID; public class MainActivity extends AppCompatActivity implements SensorEventListener { ImageButton functionF, functionB, functionL, functionR; SeekBar mySeekbar; TextView myTextview; ImageView myImageView; Switch switch_button; private SensorManager sensorManager; private final float[] accelerometerReading = new float[3]; private final float[] magnetometerReading = new float[3]; private final float[] rotationMatrix = new float[9]; private final float[] orientationAngles = new float[3]; private BluetoothAdapter btAdapter = null; private BluetoothSocket btSocket = null; private OutputStream outStream = null; private int speed = 30; private boolean inclineEnabled = false; // SPP UUID service - this should work for most devices private static final UUID BTMODULEUUID = UUID.fromString("94f39d29-7d6d-437d-973b-fba39e49d4ee"); // String for MAC address //private static String address; private static String address = "B8:27:EB:66:C5:26"; @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { /* switch(item.getItemId()) { case R.id.opt_beenden: finish(); break; // ... default: } */ if (item.getItemId() == R.id.opt_beenden) { finish(); } return super.onOptionsItemSelected(item); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // add logo + name getSupportActionBar().setDisplayShowHomeEnabled(true); getSupportActionBar().setLogo(R.mipmap.ic_launcher_zumocontrol_round); getSupportActionBar().setDisplayUseLogoEnabled(true); //Link the buttons and textViews to respective views // Initialize buttons in the view functionF = findViewById(R.id.imageButton_up); functionB = findViewById(R.id.imageButton_down); functionL = findViewById(R.id.imageButton_left); functionR = findViewById(R.id.imageButton_right); mySeekbar = findViewById(R.id.seekBar_speed); myTextview = findViewById(R.id.textView_info); myImageView = findViewById(R.id.imageView_status); mySeekbar.setProgress(speed); // set/show initial speed myTextview.setText(getString(R.string.txt_speedchanged) + speed); // show speedvalue sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); switch_button = findViewById(R.id.switchBotton1); btAdapter = BluetoothAdapter.getDefaultAdapter(); // get Bluetooth adapter checkBTState(); // set a checked state listener for switch button switch_button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { functionF.setEnabled(false); functionB.setEnabled(false); functionL.setEnabled(false); functionR.setEnabled(false); inclineEnabled = true; } else { functionF.setEnabled(true); functionB.setEnabled(true); functionL.setEnabled(true); functionR.setEnabled(true); inclineEnabled = false; } } }); // setup onTouch listeners for buttons to send commmands via BT to Raspi functionF.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN){ sendData("g"); myImageView.setImageResource(R.drawable.ic_bigup); } if(event.getAction() == MotionEvent.ACTION_UP){ sendData("r"); myImageView.setImageResource(R.drawable.ic_bigstop); } return true; } }); functionB.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN){ sendData("b"); myImageView.setImageResource(R.drawable.ic_bigdown); } if(event.getAction() == MotionEvent.ACTION_UP) { sendData("r"); myImageView.setImageResource(R.drawable.ic_bigstop); } return true; } }); functionL.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { sendData("o"); myImageView.setImageResource(R.drawable.ic_bigleft); } if (event.getAction() == MotionEvent.ACTION_UP) { sendData("r"); myImageView.setImageResource(R.drawable.ic_bigstop); } return true; } }); functionR.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { sendData("a"); myImageView.setImageResource(R.drawable.ic_bigright); } if (event.getAction() == MotionEvent.ACTION_UP) { sendData("r"); myImageView.setImageResource(R.drawable.ic_bigstop); } return true; } }); // setup seekBar change listener to react on speed change request mySeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int i, boolean b) { myTextview.setText(getString(R.string.txt_speedchanged) + seekBar.getProgress()); } @Override public void onStartTrackingTouch(SeekBar seekBar) { // bla } @Override public void onStopTrackingTouch(SeekBar seekBar) { speed = seekBar.getProgress(); sendData("*" + speed + "~"); } }); } /* //creates secure outgoing connection with BT device using UUID private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException { return device.createRfcommSocketToServiceRecord(BTMODULEUUID); } */ @Override public void onResume() { super.onResume(); Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); if (accelerometer != null) { sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI); } Sensor magneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); if (magneticField != null) { sensorManager.registerListener(this, magneticField, SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI); } //create device and set the MAC address BluetoothDevice device = btAdapter.getRemoteDevice(address); try { //btSocket = createBluetoothSocket(device); btSocket = device.createRfcommSocketToServiceRecord(BTMODULEUUID); } catch (IOException e) { Toast.makeText(getBaseContext(), getString(R.string.err_nobtsocket), Toast.LENGTH_LONG).show(); } // Establish the Bluetooth socket connection. try { Toast.makeText(getBaseContext(), getString(R.string.txt_connecting), Toast.LENGTH_LONG).show(); btSocket.connect(); } catch (IOException e) { try { btSocket.close(); } catch (IOException e2) { Toast.makeText(getBaseContext(), getString(R.string.err_noclosebtsocket), Toast.LENGTH_SHORT).show(); } } // Create a data stream so we can talk to the device try { outStream = btSocket.getOutputStream(); } catch (IOException e) { Toast.makeText(getBaseContext(), getString(R.string.err_nobtoutstream), Toast.LENGTH_SHORT).show(); } // When activity is resumed, attempt to send a piece of junk data ('x') so that it will fail if not connected // i.e don't wait for a user to press button to recognise connection failure sendData("x"); } @Override public void onPause() { super.onPause(); try { //Don't leave Bluetooth sockets open when leaving activity btSocket.close(); } catch (IOException e2) { Toast.makeText(getBaseContext(), getString(R.string.err_noclosebtsocket), Toast.LENGTH_SHORT).show(); } } //takes the UUID and creates a comms socket private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException { return device.createRfcommSocketToServiceRecord(BTMODULEUUID); } //Checks that the Android device Bluetooth is available and prompts to be turned on if off private void checkBTState() { if(btAdapter==null) { Toast.makeText(getBaseContext(), getString(R.string.err_nobtsupport), Toast.LENGTH_LONG).show(); } else { if (btAdapter.isEnabled()) { } else { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, 1); } } } //write method public void sendData(String input) { byte[] msgBuffer = input.getBytes(); //converts entered String into bytes try { outStream.write(msgBuffer); //write bytes over BT connection via outstream } catch (IOException e) { //if you cannot write, close the application Toast.makeText(getBaseContext(), getString(R.string.err_connect), Toast.LENGTH_LONG).show(); finish(); } } @Override public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { System.arraycopy(event.values, 0, accelerometerReading, 0, accelerometerReading.length); } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.length); } updateOrientationAngles(); if (inclineEnabled) { // stop identified (all angles < 30deg) if ((Math.abs(Math.toDegrees(orientationAngles[1])) < 20) && (Math.abs(Math.toDegrees(orientationAngles[2])) < 20)) { sendData("r"); myImageView.setImageResource(R.drawable.ic_bigstop); // if forward } else if ((Math.toDegrees(orientationAngles[1]) > 30) && (Math.abs(Math.toDegrees(orientationAngles[2])) < 20)) { sendData("g"); myImageView.setImageResource(R.drawable.ic_bigup); // if backward } else if ((Math.toDegrees(orientationAngles[1]) < -30) && (Math.abs(Math.toDegrees(orientationAngles[2])) < 20)) { sendData("b"); myImageView.setImageResource(R.drawable.ic_bigdown); // if spin right } else if ((Math.abs(Math.toDegrees(orientationAngles[1])) < 20) && (Math.toDegrees(orientationAngles[2]) > 30)) { sendData("a"); myImageView.setImageResource(R.drawable.ic_bigright); // if spin left } else if ((Math.abs(Math.toDegrees(orientationAngles[1])) < 20) && (Math.toDegrees(orientationAngles[2]) < -30)) { sendData("o"); myImageView.setImageResource(R.drawable.ic_bigleft); } } } // Compute the three orientation angles based on the most recent readings from // the device's accelerometer and magnetometer. public void updateOrientationAngles() { // Update rotation matrix, which is needed to update orientation angles. SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerReading, magnetometerReading); // "rotationMatrix" now has up-to-date information. SensorManager.getOrientation(rotationMatrix, orientationAngles); // "orientationAngles" now has up-to-date information. } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } }