Autoconnect. Connection in separate thread. Reconnection on error. UI
improvements
This commit is contained in:
@ -6,9 +6,8 @@
|
|||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@drawable/icon"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
<activity android:name=".MainActivity" android:configChanges="orientation"
|
<activity android:name=".MainActivity" android:configChanges="orientation"
|
||||||
|
@ -8,6 +8,7 @@ import android.support.v7.app.AppCompatActivity;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ import java.util.UUID;
|
|||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private final static int REQUEST_ENABLE_BT = 1;
|
private final static int REQUEST_ENABLE_BT = 1;
|
||||||
Button btnConnect;
|
TextView txtStatus;
|
||||||
OutputStream btOutStream;
|
OutputStream btOutStream;
|
||||||
Boolean btConnected = false;
|
Boolean btConnected = false;
|
||||||
BluetoothSocket btSocket = null;
|
BluetoothSocket btSocket = null;
|
||||||
@ -28,25 +29,33 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
SeekBar motorB;
|
SeekBar motorB;
|
||||||
TextView txtA;
|
TextView txtA;
|
||||||
TextView txtB;
|
TextView txtB;
|
||||||
int motorACommand = 2;
|
private final static int MOTOR_FULL_FORWARD_COMMAND = 4;
|
||||||
int motorBCommand = 2;
|
private final static int MOTOR_FULL_BACKWARD_COMMAND = 0;
|
||||||
|
private final static int MOTOR_STOP_COMMAND = 2;
|
||||||
|
ImageView imEngine;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
btnConnect = (Button)findViewById(R.id.btnConnect);
|
txtStatus = (TextView) findViewById(R.id.txtStatus);
|
||||||
|
|
||||||
motorA = (SeekBar)findViewById(R.id.motorA);
|
motorA = (SeekBar)findViewById(R.id.motorB);
|
||||||
motorA.setProgress(2);
|
motorA.setProgress(MOTOR_STOP_COMMAND);
|
||||||
motorA.setMax(4);
|
motorA.setMax(MOTOR_FULL_FORWARD_COMMAND);
|
||||||
motorB = (SeekBar)findViewById(R.id.motorB);
|
motorB = (SeekBar)findViewById(R.id.motorA);
|
||||||
motorB.setProgress(2);
|
motorB.setProgress(MOTOR_STOP_COMMAND);
|
||||||
motorB.setMax(4);
|
motorB.setMax(MOTOR_FULL_FORWARD_COMMAND);
|
||||||
|
motorA.setEnabled(false);
|
||||||
|
motorB.setEnabled(false);
|
||||||
|
imEngine = (ImageView)findViewById(R.id.imCE);
|
||||||
|
|
||||||
|
imEngine.setVisibility(View.VISIBLE);
|
||||||
txtA = (TextView)findViewById(R.id.txtA);
|
txtA = (TextView)findViewById(R.id.txtA);
|
||||||
txtB = (TextView)findViewById(R.id.txtB);
|
txtB = (TextView)findViewById(R.id.txtB);
|
||||||
|
txtA.setText(Integer.toString(MOTOR_STOP_COMMAND));
|
||||||
|
txtB.setText(Integer.toString(MOTOR_STOP_COMMAND));
|
||||||
|
|
||||||
motorA.setOnSeekBarChangeListener(
|
motorA.setOnSeekBarChangeListener(
|
||||||
new SeekBar.OnSeekBarChangeListener() {
|
new SeekBar.OnSeekBarChangeListener() {
|
||||||
@ -54,7 +63,6 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(SeekBar seekBar,
|
public void onProgressChanged(SeekBar seekBar,
|
||||||
int progresValue, boolean fromUser) {
|
int progresValue, boolean fromUser) {
|
||||||
motorBCommand = progresValue;
|
|
||||||
sendCommand();
|
sendCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +75,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
seekBar.setProgress(2);
|
seekBar.setProgress(MOTOR_STOP_COMMAND);
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -78,7 +86,6 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(SeekBar seekBar,
|
public void onProgressChanged(SeekBar seekBar,
|
||||||
int progresValue, boolean fromUser) {
|
int progresValue, boolean fromUser) {
|
||||||
motorACommand = progresValue;
|
|
||||||
sendCommand();
|
sendCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,14 +98,51 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
seekBar.setProgress(2);
|
seekBar.setProgress(MOTOR_STOP_COMMAND);
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
btnConnect.setOnClickListener(new View.OnClickListener() {
|
connectToCar();
|
||||||
public void onClick(View v) {
|
|
||||||
if (!btConnected) {
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
disconnectFromCar();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disconnectFromCar() {
|
||||||
|
try {
|
||||||
|
btOutStream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
//e.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
btSocket.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
//e.printStackTrace();
|
||||||
|
}
|
||||||
|
btConnected = false;
|
||||||
|
motorA.setEnabled(false);
|
||||||
|
motorB.setEnabled(false);
|
||||||
|
imEngine.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectToCar() {
|
||||||
|
new Thread() {
|
||||||
|
public void run() {
|
||||||
|
while (btSocket==null || !btSocket.isConnected()) {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
txtStatus.setText("Connecting...");
|
||||||
|
imEngine.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
if (adapter == null) {
|
if (adapter == null) {
|
||||||
// Device does not support Bluetooth
|
// Device does not support Bluetooth
|
||||||
@ -106,62 +150,83 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!adapter.isEnabled()) {
|
if (!adapter.isEnabled()) {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
txtStatus.setText("Bluetooth is not enabled. Will retry in 5 sec.");
|
||||||
|
imEngine.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
//make sure the device's bluetooth is enabled
|
//make sure the device's bluetooth is enabled
|
||||||
Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
||||||
startActivityForResult(enableBluetooth, REQUEST_ENABLE_BT);
|
startActivityForResult(enableBluetooth, REQUEST_ENABLE_BT);
|
||||||
}
|
} else {
|
||||||
|
|
||||||
final UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //UUID for serial connection
|
final UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //UUID for serial connection
|
||||||
String mac = "98:D3:31:F5:2D:2F"; //my laptop's mac adress
|
String mac = "98:D3:31:F5:2D:2F"; //my laptop's mac adress
|
||||||
BluetoothDevice device = adapter.getRemoteDevice(mac); //get remote device by mac, we assume these two devices are already paired
|
BluetoothDevice device = adapter.getRemoteDevice(mac); //get remote device by mac, we assume these two devices are already paired
|
||||||
|
|
||||||
|
|
||||||
// Get a BluetoothSocket to connect with the given BluetoothDevice
|
// Get a BluetoothSocket to connect with the given BluetoothDevice
|
||||||
btSocket = null;
|
btSocket = null;
|
||||||
btOutStream = null;
|
btOutStream = null;
|
||||||
try {
|
try {
|
||||||
btSocket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);
|
btSocket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
txtStatus.setText("Error creating socket. Will retry in 5 sec.");
|
||||||
|
imEngine.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
btSocket.connect();
|
btSocket.connect();
|
||||||
btOutStream = btSocket.getOutputStream();
|
btOutStream = btSocket.getOutputStream();
|
||||||
|
|
||||||
btConnected = true;
|
btConnected = true;
|
||||||
btnConnect.setText("Disconnect");
|
runOnUiThread(new Runnable() {
|
||||||
//now you can use out to send output via out.write
|
@Override
|
||||||
} catch (IOException e) {
|
public void run() {
|
||||||
e.printStackTrace();
|
txtStatus.setText("Connected");
|
||||||
}
|
imEngine.setVisibility(View.GONE);
|
||||||
} else {
|
motorA.setEnabled(true);
|
||||||
try {
|
motorB.setEnabled(true);
|
||||||
btOutStream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
btSocket.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
btConnected = false;
|
|
||||||
btnConnect.setText("Connect");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
final Exception er = e;
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
txtStatus.setText("Connection error. Will retry in 5 sec.");
|
||||||
|
imEngine.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(5000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendCommand() {
|
private void sendCommand() {
|
||||||
String m1 = Integer.toString(motorACommand);
|
String m1 = Integer.toString(motorA.getProgress());
|
||||||
String m2 = Integer.toString(motorBCommand);
|
String m2 = Integer.toString(motorB.getProgress());
|
||||||
txtA.setText(m1);
|
txtA.setText(m1);
|
||||||
txtB.setText(m2);
|
txtB.setText(m2);
|
||||||
try {
|
try {
|
||||||
if (btOutStream != null)
|
|
||||||
btOutStream.write((m1+m2).getBytes());
|
btOutStream.write((m1+m2).getBytes());
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
//e.printStackTrace();
|
txtStatus.setText("Disconnected");
|
||||||
|
disconnectFromCar();
|
||||||
|
connectToCar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
app/src/main/res/drawable/engine.png
Normal file
BIN
app/src/main/res/drawable/engine.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
BIN
app/src/main/res/drawable/icon.png
Normal file
BIN
app/src/main/res/drawable/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 55 KiB |
@ -9,9 +9,10 @@
|
|||||||
<SeekBar
|
<SeekBar
|
||||||
android:id="@+id/motorA"
|
android:id="@+id/motorA"
|
||||||
style="@style/Widget.AppCompat.SeekBar.Discrete"
|
style="@style/Widget.AppCompat.SeekBar.Discrete"
|
||||||
android:layout_width="182dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:max="500"
|
android:max="500"
|
||||||
@ -20,16 +21,18 @@
|
|||||||
android:rotation="270"
|
android:rotation="270"
|
||||||
android:thumb="@android:drawable/ic_notification_overlay"
|
android:thumb="@android:drawable/ic_notification_overlay"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/guideline"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<SeekBar
|
<SeekBar
|
||||||
android:id="@+id/motorB"
|
android:id="@+id/motorB"
|
||||||
style="@style/Widget.AppCompat.SeekBar.Discrete"
|
style="@style/Widget.AppCompat.SeekBar.Discrete"
|
||||||
android:layout_width="182dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:max="500"
|
android:max="500"
|
||||||
android:min="0"
|
android:min="0"
|
||||||
@ -38,18 +41,7 @@
|
|||||||
android:thumb="@android:drawable/ic_notification_overlay"
|
android:thumb="@android:drawable/ic_notification_overlay"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintStart_toStartOf="@+id/guideline"
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/btnConnect"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:text="Connect"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -60,7 +52,7 @@
|
|||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:text="TextView"
|
android:text="TextView"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/motorA" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/txtB"
|
android:id="@+id/txtB"
|
||||||
@ -70,6 +62,37 @@
|
|||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:text="TextView"
|
android:text="TextView"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/motorB" />
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
|
<android.support.constraint.Guideline
|
||||||
|
android:id="@+id/guideline"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintGuide_percent="0.5" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/txtStatus"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:text="Status..."
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imCE"
|
||||||
|
android:layout_width="101dp"
|
||||||
|
android:layout_height="63dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/guideline"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/guideline"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/engine" />
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
||||||
|
Reference in New Issue
Block a user