diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 736c7b5..0ea455b 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -9,6 +9,8 @@
+
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 75fdab9..9076de5 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,5 +1,8 @@
+
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 52dca4a..790947c 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -4,6 +4,8 @@
+
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index def6a6a..9d32e50 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,6 +2,7 @@
+
diff --git a/app/app.iml b/app/app.iml
index 22352c9..44fe74c 100644
--- a/app/app.iml
+++ b/app/app.iml
@@ -79,12 +79,14 @@
+
+
diff --git a/app/build.gradle b/app/build.gradle
index 1f6a070..e3b7cfc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -20,6 +20,7 @@ android {
}
dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:21.0.3'
+ compile project(':library')
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index cada22e..761dece 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,6 +2,9 @@
+
+
+
@@ -16,6 +20,7 @@
+
diff --git a/app/src/main/java/de/jakob/nicolas/rcontroll/MainActivity.java b/app/src/main/java/de/jakob/nicolas/rcontroll/MainActivity.java
index 05e0d28..2bc9316 100644
--- a/app/src/main/java/de/jakob/nicolas/rcontroll/MainActivity.java
+++ b/app/src/main/java/de/jakob/nicolas/rcontroll/MainActivity.java
@@ -1,27 +1,40 @@
package de.jakob.nicolas.rcontroll;
-import android.support.v7.app.ActionBarActivity;
-import android.support.v7.app.ActionBar;
-import android.support.v4.app.Fragment;
+import android.app.Activity;
+import android.bluetooth.BluetoothAdapter;
+import android.content.Intent;
import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v7.app.ActionBarActivity;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.os.Build;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Toast;
+import app.akexorcist.bluetotohspp.library.BluetoothSPP;
+import app.akexorcist.bluetotohspp.library.BluetoothState;
+import app.akexorcist.bluetotohspp.library.DeviceList;
public class MainActivity extends ActionBarActivity {
+ private static final int REQUEST_ENABLE_BT = 0;
+ public BluetoothSPP bt;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
- .add(R.id.container, new PlaceholderFragment())
+ .add(R.id.container, new BluetoothFragment())
.commit();
+
+ bt = new BluetoothSPP(this);
}
}
@@ -51,16 +64,143 @@ public boolean onOptionsItemSelected(MenuItem item) {
/**
* A placeholder fragment containing a simple view.
*/
- public static class PlaceholderFragment extends Fragment {
+ public static class BluetoothFragment extends Fragment {
+
+ private static final String LOG_BT_FRAG = "Button Fragment";
+ public BluetoothSPP bt;
+ EditText editText;
+ Button btnSend;
+ Intent lastConnected;
+
+
+ public BluetoothFragment() {
+
- public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
+
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
+
+ Button buttonConnect = (Button) rootView.findViewById(R.id.button_connect);
+ bt = new BluetoothSPP(getActivity());
+
+
+
+ editText = (EditText) rootView.findViewById(R.id.editText);
+ buttonConnect.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if(bt.getServiceState() == BluetoothState.STATE_CONNECTED) {
+ bt.disconnect();
+ } else {
+ Intent intent = new Intent(getActivity().getApplicationContext(), DeviceList.class);
+ startActivityForResult(intent, BluetoothState.REQUEST_CONNECT_DEVICE);
+ }
+ }
+ });
+
+ bt.setOnDataReceivedListener(new BluetoothSPP.OnDataReceivedListener() {
+ public void onDataReceived(byte[] data, String message) {
+ Toast.makeText(getActivity().getApplicationContext(), message, Toast.LENGTH_SHORT).show();
+
+ }
+ });
+
+ bt.setBluetoothConnectionListener(new BluetoothSPP.BluetoothConnectionListener() {
+ public void onDeviceConnected(String name, String address) {
+ Toast.makeText(getActivity().getApplicationContext()
+ , "Connected to " + name + "\n" + address
+ , Toast.LENGTH_SHORT).show();
+ }
+
+ public void onDeviceDisconnected() {
+ Toast.makeText(getActivity().getApplicationContext()
+ , "Connection lost", Toast.LENGTH_SHORT).show();
+ }
+
+ public void onDeviceConnectionFailed() {
+ Toast.makeText(getActivity().getApplicationContext()
+ , "Unable to connect", Toast.LENGTH_SHORT).show();
+ }
+ });
+
+
return rootView;
+
+
}
+
+ public void onStart() {
+ super.onStart();
+ if (!bt.isBluetoothEnabled()) {
+ Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+ startActivityForResult(intent, BluetoothState.REQUEST_ENABLE_BT);
+ } else {
+ if (!bt.isServiceAvailable()) {
+ bt.setupService();
+ bt.startService(BluetoothState.DEVICE_OTHER);
+ setup();
+ }
+ }
+
+
+ }
+
+ public void onResume(){
+ super.onResume();
+
+
+ }
+
+ public void onPause(){
+ super.onPause();
+ bt.stopService();
+
+ }
+
+
+ public void setup() {
+ btnSend = (Button) getActivity().findViewById(R.id.button_send);
+ btnSend.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ bt.send(editText.getText().toString(), true);
+ Log.e("ButtonSEND", "BUTTON SEND PRESSED" + editText.getText().toString());
+ }
+ });
+
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+
+ if (requestCode == BluetoothState.REQUEST_CONNECT_DEVICE) {
+ if (resultCode == Activity.RESULT_OK) {
+ if (bt != null && data != null) {
+ bt.connect(data);
+ lastConnected = data;
+ }
+
+
+ } else if (requestCode == BluetoothState.REQUEST_ENABLE_BT) {
+ if (resultCode == Activity.RESULT_OK) {
+ bt.setupService();
+ bt.startService(BluetoothState.DEVICE_OTHER);
+
+ } else {
+ Toast.makeText(getActivity().getApplicationContext()
+ , "Bluetooth was not enabled."
+ , Toast.LENGTH_SHORT).show();
+ getActivity().finish();
+ }
+ }
+ }
+ }
+
+
+
}
}
diff --git a/app/src/main/java/de/jakob/nicolas/rcontroll/SimpleActivity.java b/app/src/main/java/de/jakob/nicolas/rcontroll/SimpleActivity.java
new file mode 100644
index 0000000..b92ccdc
--- /dev/null
+++ b/app/src/main/java/de/jakob/nicolas/rcontroll/SimpleActivity.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2014 Akexorcist
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package de.jakob.nicolas.rcontroll;
+
+import android.app.Activity;
+import android.bluetooth.BluetoothAdapter;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.Toast;
+
+import app.akexorcist.bluetotohspp.library.BluetoothSPP;
+import app.akexorcist.bluetotohspp.library.BluetoothSPP.BluetoothConnectionListener;
+import app.akexorcist.bluetotohspp.library.BluetoothSPP.OnDataReceivedListener;
+import app.akexorcist.bluetotohspp.library.BluetoothState;
+import app.akexorcist.bluetotohspp.library.DeviceList;
+
+public class SimpleActivity extends Activity {
+ BluetoothSPP bt;
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_simple);
+
+ bt = new BluetoothSPP(this);
+
+ if(!bt.isBluetoothAvailable()) {
+ Toast.makeText(getApplicationContext()
+ , "Bluetooth is not available"
+ , Toast.LENGTH_SHORT).show();
+ finish();
+ }
+
+ bt.setOnDataReceivedListener(new OnDataReceivedListener() {
+ public void onDataReceived(byte[] data, String message) {
+ Toast.makeText(SimpleActivity.this, message, Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ bt.setBluetoothConnectionListener(new BluetoothConnectionListener() {
+ public void onDeviceConnected(String name, String address) {
+ Toast.makeText(getApplicationContext()
+ , "Connected to " + name + "\n" + address
+ , Toast.LENGTH_SHORT).show();
+ }
+
+ public void onDeviceDisconnected() {
+ Toast.makeText(getApplicationContext()
+ , "Connection lost", Toast.LENGTH_SHORT).show();
+ }
+
+ public void onDeviceConnectionFailed() {
+ Toast.makeText(getApplicationContext()
+ , "Unable to connect", Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ Button btnConnect = (Button)findViewById(R.id.btnConnect);
+ btnConnect.setOnClickListener(new OnClickListener(){
+ public void onClick(View v){
+ if(bt.getServiceState() == BluetoothState.STATE_CONNECTED) {
+ bt.disconnect();
+ } else {
+ Intent intent = new Intent(getApplicationContext(), DeviceList.class);
+ startActivityForResult(intent, BluetoothState.REQUEST_CONNECT_DEVICE);
+ }
+ }
+ });
+ }
+
+ public void onDestroy() {
+ super.onDestroy();
+ bt.stopService();
+ }
+
+ public void onStart() {
+ super.onStart();
+ if (!bt.isBluetoothEnabled()) {
+ Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+ startActivityForResult(intent, BluetoothState.REQUEST_ENABLE_BT);
+ } else {
+ if(!bt.isServiceAvailable()) {
+ bt.setupService();
+ bt.startService(BluetoothState.DEVICE_OTHER);
+ setup();
+ }
+ }
+ }
+
+ public void setup() {
+ Button btnSend = (Button)findViewById(R.id.btnSend);
+ btnSend.setOnClickListener(new OnClickListener(){
+ public void onClick(View v){
+ bt.send("1", true);
+ }
+ });
+ }
+
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if(requestCode == BluetoothState.REQUEST_CONNECT_DEVICE) {
+ if(resultCode == Activity.RESULT_OK)
+ bt.connect(data);
+ } else if(requestCode == BluetoothState.REQUEST_ENABLE_BT) {
+ if(resultCode == Activity.RESULT_OK) {
+ bt.setupService();
+ bt.startService(BluetoothState.DEVICE_OTHER);
+ setup();
+ } else {
+ Toast.makeText(getApplicationContext()
+ , "Bluetooth was not enabled."
+ , Toast.LENGTH_SHORT).show();
+ finish();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_simple.xml b/app/src/main/res/layout/activity_simple.xml
new file mode 100644
index 0000000..6cc3330
--- /dev/null
+++ b/app/src/main/res/layout/activity_simple.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml
index bb3dd46..9361157 100644
--- a/app/src/main/res/layout/fragment_main.xml
+++ b/app/src/main/res/layout/fragment_main.xml
@@ -6,7 +6,29 @@
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity$PlaceholderFragment">
-
+
+
+
+
+
diff --git a/build.gradle b/build.gradle
index fc67c9c..6356aab 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:1.0.0-rc2'
+ classpath 'com.android.tools.build:gradle:1.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/import-summary.txt b/import-summary.txt
new file mode 100644
index 0000000..765eb9e
--- /dev/null
+++ b/import-summary.txt
@@ -0,0 +1,35 @@
+ECLIPSE ANDROID PROJECT IMPORT SUMMARY
+======================================
+
+Ignored Files:
+--------------
+The following files were *not* copied into the new Gradle project; you
+should evaluate whether these are still needed in your project and if
+so manually move them:
+
+* .gitignore
+* README.md
+* proguard.cfg
+
+Moved Files:
+------------
+Android Gradle projects use a different directory structure than ADT
+Eclipse projects. Here's how the projects were restructured:
+
+* AndroidManifest.xml => joystickView\src\main\AndroidManifest.xml
+* src\ => joystickView\src\main\java\
+
+Next Steps:
+-----------
+You can now build the project. The Gradle project needs network
+connectivity to download dependencies.
+
+Bugs:
+-----
+If for some reason your project does not build, and you determine that
+it is due to a bug or limitation of the Eclipse to Gradle importer,
+please file a bug at http://b.android.com with category
+Component-Tools.
+
+(This import summary is for your information only, and can be deleted
+after import once you are satisfied with the results.)
diff --git a/joystickView/build.gradle b/joystickView/build.gradle
new file mode 100644
index 0000000..6d53640
--- /dev/null
+++ b/joystickView/build.gradle
@@ -0,0 +1,17 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 21
+ buildToolsVersion "21.1.2"
+
+ defaultConfig {
+ minSdkVersion 16
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
+ }
+ }
+}
diff --git a/joystickView/build/generated/source/buildConfig/debug/com/zerokol/views/BuildConfig.java b/joystickView/build/generated/source/buildConfig/debug/com/zerokol/views/BuildConfig.java
new file mode 100644
index 0000000..b26924b
--- /dev/null
+++ b/joystickView/build/generated/source/buildConfig/debug/com/zerokol/views/BuildConfig.java
@@ -0,0 +1,13 @@
+/**
+ * Automatically generated file. DO NOT MODIFY
+ */
+package com.zerokol.views;
+
+public final class BuildConfig {
+ public static final boolean DEBUG = Boolean.parseBoolean("true");
+ public static final String APPLICATION_ID = "com.zerokol.views";
+ public static final String BUILD_TYPE = "debug";
+ public static final String FLAVOR = "";
+ public static final int VERSION_CODE = 3;
+ public static final String VERSION_NAME = "";
+}
diff --git a/joystickView/build/generated/source/buildConfig/test/debug/com/zerokol/views/test/BuildConfig.java b/joystickView/build/generated/source/buildConfig/test/debug/com/zerokol/views/test/BuildConfig.java
new file mode 100644
index 0000000..8aa267e
--- /dev/null
+++ b/joystickView/build/generated/source/buildConfig/test/debug/com/zerokol/views/test/BuildConfig.java
@@ -0,0 +1,13 @@
+/**
+ * Automatically generated file. DO NOT MODIFY
+ */
+package com.zerokol.views.test;
+
+public final class BuildConfig {
+ public static final boolean DEBUG = Boolean.parseBoolean("true");
+ public static final String APPLICATION_ID = "com.zerokol.views.test";
+ public static final String BUILD_TYPE = "debug";
+ public static final String FLAVOR = "";
+ public static final int VERSION_CODE = -1;
+ public static final String VERSION_NAME = "";
+}
diff --git a/joystickView/joystickView.iml b/joystickView/joystickView.iml
new file mode 100644
index 0000000..00ba5ad
--- /dev/null
+++ b/joystickView/joystickView.iml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/joystickView/src/main/AndroidManifest.xml b/joystickView/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ca61238
--- /dev/null
+++ b/joystickView/src/main/AndroidManifest.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/joystickView/src/main/java/com/zerokol/views/JoystickView.java b/joystickView/src/main/java/com/zerokol/views/JoystickView.java
new file mode 100644
index 0000000..b811ef9
--- /dev/null
+++ b/joystickView/src/main/java/com/zerokol/views/JoystickView.java
@@ -0,0 +1,271 @@
+package com.zerokol.views;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+public class JoystickView extends View implements Runnable {
+ // Constants
+ private final double RAD = 57.2957795;
+ public final static long DEFAULT_LOOP_INTERVAL = 100; // 100 ms
+ public final static int FRONT = 3;
+ public final static int FRONT_RIGHT = 4;
+ public final static int RIGHT = 5;
+ public final static int RIGHT_BOTTOM = 6;
+ public final static int BOTTOM = 7;
+ public final static int BOTTOM_LEFT = 8;
+ public final static int LEFT = 1;
+ public final static int LEFT_FRONT = 2;
+ // Variables
+ private OnJoystickMoveListener onJoystickMoveListener; // Listener
+ private Thread thread = new Thread(this);
+ private long loopInterval = DEFAULT_LOOP_INTERVAL;
+ private int xPosition = 0; // Touch x position
+ private int yPosition = 0; // Touch y position
+ private double centerX = 0; // Center view x position
+ private double centerY = 0; // Center view y position
+ private Paint mainCircle;
+ private Paint secondaryCircle;
+ private Paint button;
+ private Paint horizontalLine;
+ private Paint verticalLine;
+ private int joystickRadius;
+ private int buttonRadius;
+ private int lastAngle = 0;
+ private int lastPower = 0;
+
+ public JoystickView(Context context) {
+ super(context);
+ }
+
+ public JoystickView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initJoystickView();
+ }
+
+ public JoystickView(Context context, AttributeSet attrs, int defaultStyle) {
+ super(context, attrs, defaultStyle);
+ initJoystickView();
+ }
+
+ protected void initJoystickView() {
+ mainCircle = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mainCircle.setColor(Color.WHITE);
+ mainCircle.setStyle(Paint.Style.FILL_AND_STROKE);
+
+ secondaryCircle = new Paint();
+ secondaryCircle.setColor(Color.GREEN);
+ secondaryCircle.setStyle(Paint.Style.STROKE);
+
+ verticalLine = new Paint();
+ verticalLine.setStrokeWidth(5);
+ verticalLine.setColor(Color.RED);
+
+ horizontalLine = new Paint();
+ horizontalLine.setStrokeWidth(2);
+ horizontalLine.setColor(Color.BLACK);
+
+ button = new Paint(Paint.ANTI_ALIAS_FLAG);
+ button.setColor(Color.RED);
+ button.setStyle(Paint.Style.FILL);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ }
+
+ @Override
+ protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld) {
+ super.onSizeChanged(xNew, yNew, xOld, yOld);
+ // before measure, get the center of view
+ xPosition = (int) getWidth() / 2;
+ yPosition = (int) getWidth() / 2;
+ int d = Math.min(xNew, yNew);
+ buttonRadius = (int) (d / 2 * 0.25);
+ joystickRadius = (int) (d / 2 * 0.75);
+
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // setting the measured values to resize the view to a certain width and
+ // height
+ int d = Math.min(measure(widthMeasureSpec), measure(heightMeasureSpec));
+
+ setMeasuredDimension(d, d);
+
+ }
+
+ private int measure(int measureSpec) {
+ int result = 0;
+
+ // Decode the measurement specifications.
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.UNSPECIFIED) {
+ // Return a default size of 200 if no bounds are specified.
+ result = 200;
+ } else {
+ // As you want to fill the available space
+ // always return the full available bounds.
+ result = specSize;
+ }
+ return result;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ // super.onDraw(canvas);
+ centerX = (getWidth()) / 2;
+ centerY = (getHeight()) / 2;
+
+ // painting the main circle
+ canvas.drawCircle((int) centerX, (int) centerY, joystickRadius,
+ mainCircle);
+ // painting the secondary circle
+ canvas.drawCircle((int) centerX, (int) centerY, joystickRadius / 2,
+ secondaryCircle);
+ // paint lines
+ canvas.drawLine((float) centerX, (float) centerY, (float) centerX,
+ (float) (centerY - joystickRadius), verticalLine);
+ canvas.drawLine((float) (centerX - joystickRadius), (float) centerY,
+ (float) (centerX + joystickRadius), (float) centerY,
+ horizontalLine);
+ canvas.drawLine((float) centerX, (float) (centerY + joystickRadius),
+ (float) centerX, (float) centerY, horizontalLine);
+
+ // painting the move button
+ canvas.drawCircle(xPosition, yPosition, buttonRadius, button);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ xPosition = (int) event.getX();
+ yPosition = (int) event.getY();
+ double abs = Math.sqrt((xPosition - centerX) * (xPosition - centerX)
+ + (yPosition - centerY) * (yPosition - centerY));
+ if (abs > joystickRadius) {
+ xPosition = (int) ((xPosition - centerX) * joystickRadius / abs + centerX);
+ yPosition = (int) ((yPosition - centerY) * joystickRadius / abs + centerY);
+ }
+ invalidate();
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ xPosition = (int) centerX;
+ yPosition = (int) centerY;
+ thread.interrupt();
+ if (onJoystickMoveListener != null)
+ onJoystickMoveListener.onValueChanged(getAngle(), getPower(),
+ getDirection());
+ }
+ if (onJoystickMoveListener != null
+ && event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (thread != null && thread.isAlive()) {
+ thread.interrupt();
+ }
+ thread = new Thread(this);
+ thread.start();
+ if (onJoystickMoveListener != null)
+ onJoystickMoveListener.onValueChanged(getAngle(), getPower(),
+ getDirection());
+ }
+ return true;
+ }
+
+ private int getAngle() {
+ if (xPosition > centerX) {
+ if (yPosition < centerY) {
+ return lastAngle = (int) (Math.atan((yPosition - centerY)
+ / (xPosition - centerX))
+ * RAD + 90);
+ } else if (yPosition > centerY) {
+ return lastAngle = (int) (Math.atan((yPosition - centerY)
+ / (xPosition - centerX)) * RAD) + 90;
+ } else {
+ return lastAngle = 90;
+ }
+ } else if (xPosition < centerX) {
+ if (yPosition < centerY) {
+ return lastAngle = (int) (Math.atan((yPosition - centerY)
+ / (xPosition - centerX))
+ * RAD - 90);
+ } else if (yPosition > centerY) {
+ return lastAngle = (int) (Math.atan((yPosition - centerY)
+ / (xPosition - centerX)) * RAD) - 90;
+ } else {
+ return lastAngle = -90;
+ }
+ } else {
+ if (yPosition <= centerY) {
+ return lastAngle = 0;
+ } else {
+ if (lastAngle < 0) {
+ return lastAngle = -180;
+ } else {
+ return lastAngle = 180;
+ }
+ }
+ }
+ }
+
+ private int getPower() {
+ return (int) (100 * Math.sqrt((xPosition - centerX)
+ * (xPosition - centerX) + (yPosition - centerY)
+ * (yPosition - centerY)) / joystickRadius);
+ }
+
+ private int getDirection() {
+ if (lastPower == 0 && lastAngle == 0) {
+ return 0;
+ }
+ int a = 0;
+ if (lastAngle <= 0) {
+ a = (lastAngle * -1) + 90;
+ } else if (lastAngle > 0) {
+ if (lastAngle <= 90) {
+ a = 90 - lastAngle;
+ } else {
+ a = 360 - (lastAngle - 90);
+ }
+ }
+
+ int direction = (int) (((a + 22) / 45) + 1);
+
+ if (direction > 8) {
+ direction = 1;
+ }
+ return direction;
+ }
+
+ public void setOnJoystickMoveListener(OnJoystickMoveListener listener,
+ long repeatInterval) {
+ this.onJoystickMoveListener = listener;
+ this.loopInterval = repeatInterval;
+ }
+
+ public static interface OnJoystickMoveListener {
+ public void onValueChanged(int angle, int power, int direction);
+ }
+
+ @Override
+ public void run() {
+ while (!Thread.interrupted()) {
+ post(new Runnable() {
+ public void run() {
+ if (onJoystickMoveListener != null)
+ onJoystickMoveListener.onValueChanged(getAngle(),
+ getPower(), getDirection());
+ }
+ });
+ try {
+ Thread.sleep(loopInterval);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/library/.gitignore b/library/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/library/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/library/build.gradle b/library/build.gradle
new file mode 100644
index 0000000..0a675d8
--- /dev/null
+++ b/library/build.gradle
@@ -0,0 +1,54 @@
+apply plugin: 'com.android.library'
+
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.+'
+ }
+}
+
+apply plugin: 'maven'
+apply plugin: 'signing'
+version = "1.0.0"
+group = "co.something"
+
+repositories {
+ mavenCentral()
+}
+
+android {
+ compileSdkVersion 21
+ buildToolsVersion "21.1.2"
+
+ defaultConfig {
+ // applicationId "app.akexorcist.bluetotohspp.library"
+ versionCode 1
+ versionName "1.0"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ sourceSets {
+ main {
+ java {
+ srcDir 'java'
+ }
+ res {
+ srcDir 'res'
+ }
+ manifest {
+ srcFile '/src/main/AndroidManifest.xml'
+ }
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+}
diff --git a/library/library.iml b/library/library.iml
new file mode 100644
index 0000000..4e2a261
--- /dev/null
+++ b/library/library.iml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro
new file mode 100644
index 0000000..bd731c6
--- /dev/null
+++ b/library/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in D:/My Program/Android Developer/ADT/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/library/src/androidTest/java/app/akexorcist/bluetotohspp/library/ApplicationTest.java b/library/src/androidTest/java/app/akexorcist/bluetotohspp/library/ApplicationTest.java
new file mode 100644
index 0000000..b2d8048
--- /dev/null
+++ b/library/src/androidTest/java/app/akexorcist/bluetotohspp/library/ApplicationTest.java
@@ -0,0 +1,13 @@
+package app.akexorcist.bluetotohspp.library;
+
+import android.app.Application;
+import android.test.ApplicationTestCase;
+
+/**
+ * Testing Fundamentals
+ */
+public class ApplicationTest extends ApplicationTestCase {
+ public ApplicationTest() {
+ super(Application.class);
+ }
+}
\ No newline at end of file
diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..dd358ec
--- /dev/null
+++ b/library/src/main/AndroidManifest.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/library/src/main/java/app/akexorcist/bluetotohspp/library/BluetoothSPP.java b/library/src/main/java/app/akexorcist/bluetotohspp/library/BluetoothSPP.java
new file mode 100644
index 0000000..43b5edc
--- /dev/null
+++ b/library/src/main/java/app/akexorcist/bluetotohspp/library/BluetoothSPP.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2014 Akexorcist
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app.akexorcist.bluetotohspp.library;
+
+import android.annotation.SuppressLint;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+@SuppressLint("NewApi")
+public class BluetoothSPP {
+ // Listener for Bluetooth Status & Connection
+ private BluetoothStateListener mBluetoothStateListener = null;
+ private OnDataReceivedListener mDataReceivedListener = null;
+ private BluetoothConnectionListener mBluetoothConnectionListener = null;
+ private AutoConnectionListener mAutoConnectionListener = null;
+
+ // Context from activity which call this class
+ private Context mContext;
+
+ // Local Bluetooth adapter
+ private BluetoothAdapter mBluetoothAdapter = null;
+
+ // Member object for the chat services
+ private BluetoothService mChatService = null;
+
+ // Name and Address of the connected device
+ private String mDeviceName = null;
+ private String mDeviceAddress = null;
+
+ private boolean isAutoConnecting = false;
+ private boolean isAutoConnectionEnabled = false;
+ private boolean isConnected = false;
+ private boolean isConnecting = false;
+ private boolean isServiceRunning = false;
+
+ private String keyword = "";
+ private boolean isAndroid = BluetoothState.DEVICE_ANDROID;
+
+ private BluetoothConnectionListener bcl;
+ private int c = 0;
+
+ public BluetoothSPP(Context context) {
+ mContext = context;
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ }
+
+ public interface BluetoothStateListener {
+ public void onServiceStateChanged(int state);
+ }
+
+ public interface OnDataReceivedListener {
+ public void onDataReceived(byte[] data, String message);
+ }
+
+ public interface BluetoothConnectionListener {
+ public void onDeviceConnected(String name, String address);
+ public void onDeviceDisconnected();
+ public void onDeviceConnectionFailed();
+ }
+
+ public interface AutoConnectionListener {
+ public void onAutoConnectionStarted();
+ public void onNewConnection(String name, String address);
+ }
+
+ public boolean isBluetoothAvailable() {
+ try {
+ if (mBluetoothAdapter == null || mBluetoothAdapter.getAddress().equals(null))
+ return false;
+ } catch (NullPointerException e) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean isBluetoothEnabled() {
+ return mBluetoothAdapter.isEnabled();
+ }
+
+ public boolean isServiceAvailable() {
+ return mChatService != null;
+ }
+
+ public boolean isAutoConnecting() {
+ return isAutoConnecting;
+ }
+
+ public boolean startDiscovery() {
+ return mBluetoothAdapter.startDiscovery();
+ }
+
+ public boolean isDiscovery() {
+ return mBluetoothAdapter.isDiscovering();
+ }
+
+ public boolean cancelDiscovery() {
+ return mBluetoothAdapter.cancelDiscovery();
+ }
+
+ public void setupService() {
+ mChatService = new BluetoothService(mContext, mHandler);
+ }
+
+ public BluetoothAdapter getBluetoothAdapter() {
+ return mBluetoothAdapter;
+ }
+
+ public int getServiceState() {
+ if(mChatService != null)
+ return mChatService.getState();
+ else
+ return -1;
+ }
+
+ public void startService(boolean isAndroid) {
+ if (mChatService != null) {
+ if (mChatService.getState() == BluetoothState.STATE_NONE) {
+ isServiceRunning = true;
+ mChatService.start(isAndroid);
+ BluetoothSPP.this.isAndroid = isAndroid;
+ }
+ }
+ }
+
+ public void stopService() {
+ if (mChatService != null) {
+ isServiceRunning = false;
+ mChatService.stop();
+ }
+ new Handler().postDelayed(new Runnable() {
+ public void run() {
+ if (mChatService != null) {
+ isServiceRunning = false;
+ mChatService.stop();
+ }
+ }
+ }, 500);
+ }
+
+ public void setDeviceTarget(boolean isAndroid) {
+ stopService();
+ startService(isAndroid);
+ BluetoothSPP.this.isAndroid = isAndroid;
+ }
+
+ @SuppressLint("HandlerLeak")
+ private final Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case BluetoothState.MESSAGE_WRITE:
+ break;
+ case BluetoothState.MESSAGE_READ:
+ byte[] readBuf = (byte[]) msg.obj;
+ String readMessage = new String(readBuf);
+ if(readBuf != null && readBuf.length > 0) {
+ if(mDataReceivedListener != null)
+ mDataReceivedListener.onDataReceived(readBuf, readMessage);
+ }
+ break;
+ case BluetoothState.MESSAGE_DEVICE_NAME:
+ mDeviceName = msg.getData().getString(BluetoothState.DEVICE_NAME);
+ mDeviceAddress = msg.getData().getString(BluetoothState.DEVICE_ADDRESS);
+ if(mBluetoothConnectionListener != null)
+ mBluetoothConnectionListener.onDeviceConnected(mDeviceName, mDeviceAddress);
+ isConnected = true;
+ break;
+ case BluetoothState.MESSAGE_TOAST:
+ Toast.makeText(mContext, msg.getData().getString(BluetoothState.TOAST)
+ , Toast.LENGTH_SHORT).show();
+ break;
+ case BluetoothState.MESSAGE_STATE_CHANGE:
+ if(mBluetoothStateListener != null)
+ mBluetoothStateListener.onServiceStateChanged(msg.arg1);
+ if(isConnected && msg.arg1 != BluetoothState.STATE_CONNECTED) {
+ if(mBluetoothConnectionListener != null)
+ mBluetoothConnectionListener.onDeviceDisconnected();
+ if(isAutoConnectionEnabled) {
+ isAutoConnectionEnabled = false;
+ autoConnect(keyword);
+ }
+ isConnected = false;
+ mDeviceName = null;
+ mDeviceAddress = null;
+ }
+
+ if(!isConnecting && msg.arg1 == BluetoothState.STATE_CONNECTING) {
+ isConnecting = true;
+ } else if(isConnecting) {
+ if(msg.arg1 != BluetoothState.STATE_CONNECTED) {
+ if(mBluetoothConnectionListener != null)
+ mBluetoothConnectionListener.onDeviceConnectionFailed();
+ }
+ isConnecting = false;
+ }
+ break;
+ }
+ }
+ };
+
+ public void stopAutoConnect() {
+ isAutoConnectionEnabled = false;
+ }
+
+ public void connect(Intent data) {
+ String address = data.getExtras().getString(BluetoothState.EXTRA_DEVICE_ADDRESS);
+ BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
+ if(device != null) {
+ mChatService.connect(device);
+
+ }
+ }
+
+ public void connect(String address) {
+ BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
+ mChatService.connect(device);
+ }
+
+ public void disconnect() {
+ if(mChatService != null) {
+ isServiceRunning = false;
+ mChatService.stop();
+ if(mChatService.getState() == BluetoothState.STATE_NONE) {
+ isServiceRunning = true;
+ mChatService.start(BluetoothSPP.this.isAndroid);
+ }
+ }
+ }
+
+ public void setBluetoothStateListener (BluetoothStateListener listener) {
+ mBluetoothStateListener = listener;
+ }
+
+ public void setOnDataReceivedListener (OnDataReceivedListener listener) {
+ mDataReceivedListener = listener;
+ }
+
+ public void setBluetoothConnectionListener (BluetoothConnectionListener listener) {
+ mBluetoothConnectionListener = listener;
+ }
+
+ public void setAutoConnectionListener(AutoConnectionListener listener) {
+ mAutoConnectionListener = listener;
+ }
+
+ public void enable() {
+ mBluetoothAdapter.enable();
+ }
+
+ public void send(byte[] data, boolean CRLF) {
+ if(mChatService.getState() == BluetoothState.STATE_CONNECTED) {
+ if(CRLF) {
+ byte[] data2 = new byte[data.length + 2];
+ for(int i = 0 ; i < data.length ; i++)
+ data2[i] = data[i];
+ data2[data2.length - 0] = 0x0A;
+ data2[data2.length] = 0x0D;
+ mChatService.write(data2);
+ } else {
+ mChatService.write(data);
+ }
+ }
+ }
+
+ public void send(String data, boolean CRLF) {
+ if(mChatService.getState() == BluetoothState.STATE_CONNECTED) {
+ if(CRLF)
+ data += "\r\n";
+ mChatService.write(data.getBytes());
+ }
+ }
+
+ public String getConnectedDeviceName() {
+ return mDeviceName;
+ }
+
+ public String getConnectedDeviceAddress() {
+ return mDeviceAddress;
+ }
+
+ public String[] getPairedDeviceName() {
+ int c = 0;
+ Set devices = mBluetoothAdapter.getBondedDevices();
+ String[] name_list = new String[devices.size()];
+ for(BluetoothDevice device : devices) {
+ name_list[c] = device.getName();
+ c++;
+ }
+ return name_list;
+ }
+
+ public String[] getPairedDeviceAddress() {
+ int c = 0;
+ Set devices = mBluetoothAdapter.getBondedDevices();
+ String[] address_list = new String[devices.size()];
+ for(BluetoothDevice device : devices) {
+ address_list[c] = device.getAddress();
+ c++;
+ }
+ return address_list;
+ }
+
+
+ public void autoConnect(String keywordName) {
+ if(!isAutoConnectionEnabled) {
+ keyword = keywordName;
+ isAutoConnectionEnabled = true;
+ isAutoConnecting = true;
+ if(mAutoConnectionListener != null)
+ mAutoConnectionListener.onAutoConnectionStarted();
+ final ArrayList arr_filter_address = new ArrayList();
+ final ArrayList arr_filter_name = new ArrayList();
+ String[] arr_name = getPairedDeviceName();
+ String[] arr_address = getPairedDeviceAddress();
+ for(int i = 0 ; i < arr_name.length ; i++) {
+ if(arr_name[i].contains(keywordName)) {
+ arr_filter_address.add(arr_address[i]);
+ arr_filter_name.add(arr_name[i]);
+ }
+ }
+
+ bcl = new BluetoothConnectionListener() {
+ public void onDeviceConnected(String name, String address) {
+ bcl = null;
+ isAutoConnecting = false;
+ }
+
+ public void onDeviceDisconnected() { }
+ public void onDeviceConnectionFailed() {
+ Log.e("CHeck", "Failed");
+ if(isServiceRunning) {
+ if(isAutoConnectionEnabled) {
+ c++;
+ if(c >= arr_filter_address.size())
+ c = 0;
+ connect(arr_filter_address.get(c));
+ Log.e("CHeck", "Connect");
+ if(mAutoConnectionListener != null)
+ mAutoConnectionListener.onNewConnection(arr_filter_name.get(c)
+ , arr_filter_address.get(c));
+ } else {
+ bcl = null;
+ isAutoConnecting = false;
+ }
+ }
+ }
+ };
+
+ setBluetoothConnectionListener(bcl);
+ c = 0;
+ if(mAutoConnectionListener != null)
+ mAutoConnectionListener.onNewConnection(arr_name[c], arr_address[c]);
+ if(arr_filter_address.size() > 0)
+ connect(arr_filter_address.get(c));
+ else
+ Toast.makeText(mContext, "Device name mismatch", Toast.LENGTH_SHORT).show();
+ }
+ }
+}
diff --git a/library/src/main/java/app/akexorcist/bluetotohspp/library/BluetoothService.java b/library/src/main/java/app/akexorcist/bluetotohspp/library/BluetoothService.java
new file mode 100644
index 0000000..a136ca2
--- /dev/null
+++ b/library/src/main/java/app/akexorcist/bluetotohspp/library/BluetoothService.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app.akexorcist.bluetotohspp.library;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.UUID;
+
+import android.annotation.SuppressLint;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothSocket;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+@SuppressLint("NewApi")
+public class BluetoothService {
+ // Debugging
+ private static final String TAG = "Bluetooth Service";
+
+ // Name for the SDP record when creating server socket
+ private static final String NAME_SECURE = "Bluetooth Secure";
+
+ // Unique UUID for this application
+ private static final UUID UUID_ANDROID_DEVICE =
+ UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
+ private static final UUID UUID_OTHER_DEVICE =
+ UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
+
+ // Member fields
+ private final BluetoothAdapter mAdapter;
+ private final Handler mHandler;
+ private AcceptThread mSecureAcceptThread;
+ private ConnectThread mConnectThread;
+ private ConnectedThread mConnectedThread;
+ private int mState;
+ private boolean isAndroid = BluetoothState.DEVICE_ANDROID;
+
+ // Constructor. Prepares a new BluetoothChat session
+ // context : The UI Activity Context
+ // handler : A Handler to send messages back to the UI Activity
+ public BluetoothService(Context context, Handler handler) {
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mState = BluetoothState.STATE_NONE;
+ mHandler = handler;
+ }
+
+
+ // Set the current state of the chat connection
+ // state : An integer defining the current connection state
+ private synchronized void setState(int state) {
+ Log.d(TAG, "setState() " + mState + " -> " + state);
+ mState = state;
+
+ // Give the new state to the Handler so the UI Activity can update
+ mHandler.obtainMessage(BluetoothState.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
+ }
+
+ // Return the current connection state.
+ public synchronized int getState() {
+ return mState;
+ }
+
+ // Start the chat service. Specifically start AcceptThread to begin a
+ // session in listening (server) mode. Called by the Activity onResume()
+ public synchronized void start(boolean isAndroid) {
+ // Cancel any thread attempting to make a connection
+ if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
+ // Cancel any thread currently running a connection
+ if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
+
+ setState(BluetoothState.STATE_LISTEN);
+
+ // Start the thread to listen on a BluetoothServerSocket
+ if (mSecureAcceptThread == null) {
+ mSecureAcceptThread = new AcceptThread(isAndroid);
+ mSecureAcceptThread.start();
+ BluetoothService.this.isAndroid = isAndroid;
+ }
+ }
+
+ // Start the ConnectThread to initiate a connection to a remote device
+ // device : The BluetoothDevice to connect
+ // secure : Socket Security type - Secure (true) , Insecure (false)
+ public synchronized void connect(BluetoothDevice device) {
+ // Cancel any thread attempting to make a connection
+ if (mState == BluetoothState.STATE_CONNECTING) {
+ if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
+ }
+
+ // Cancel any thread currently running a connection
+ if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
+
+ // Start the thread to connect with the given device
+ mConnectThread = new ConnectThread(device);
+ mConnectThread.start();
+ setState(BluetoothState.STATE_CONNECTING);
+ }
+
+ /**
+ * Start the ConnectedThread to begin managing a Bluetooth connection
+ * @param socket The BluetoothSocket on which the connection was made
+ * @param device The BluetoothDevice that has been connected
+ */
+ public synchronized void connected(BluetoothSocket socket, BluetoothDevice
+ device, final String socketType) {
+ // Cancel the thread that completed the connection
+ if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
+
+ // Cancel any thread currently running a connection
+ if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
+
+ // Cancel the accept thread because we only want to connect to one device
+ if (mSecureAcceptThread != null) {
+ mSecureAcceptThread.cancel();
+ mSecureAcceptThread = null;
+ }
+
+ // Start the thread to manage the connection and perform transmissions
+ mConnectedThread = new ConnectedThread(socket, socketType);
+ mConnectedThread.start();
+
+ // Send the name of the connected device back to the UI Activity
+ Message msg = mHandler.obtainMessage(BluetoothState.MESSAGE_DEVICE_NAME);
+ Bundle bundle = new Bundle();
+ bundle.putString(BluetoothState.DEVICE_NAME, device.getName());
+ bundle.putString(BluetoothState.DEVICE_ADDRESS, device.getAddress());
+ msg.setData(bundle);
+ mHandler.sendMessage(msg);
+
+ setState(BluetoothState.STATE_CONNECTED);
+ }
+
+ // Stop all threads
+ public synchronized void stop() {
+ if (mConnectThread != null) {
+ mConnectThread.cancel();
+ mConnectThread = null;
+ }
+
+ if (mConnectedThread != null) {
+ mConnectedThread.cancel();
+ mConnectedThread = null;
+ }
+
+ if (mSecureAcceptThread != null) {
+ mSecureAcceptThread.cancel();
+ mSecureAcceptThread.kill();
+ mSecureAcceptThread = null;
+ }
+ setState(BluetoothState.STATE_NONE);
+ }
+
+ // Write to the ConnectedThread in an unsynchronized manner
+ // out : The bytes to write
+ public void write(byte[] out) {
+ // Create temporary object
+ ConnectedThread r;
+ // Synchronize a copy of the ConnectedThread
+ synchronized (this) {
+ if (mState != BluetoothState.STATE_CONNECTED) return;
+ r = mConnectedThread;
+ }
+ // Perform the write unsynchronized
+ r.write(out);
+ }
+
+ // Indicate that the connection attempt failed and notify the UI Activity
+ private void connectionFailed() {
+ // Start the service over to restart listening mode
+ BluetoothService.this.start(BluetoothService.this.isAndroid);
+ }
+
+ // Indicate that the connection was lost and notify the UI Activity
+ private void connectionLost() {
+ // Start the service over to restart listening mode
+ BluetoothService.this.start(BluetoothService.this.isAndroid);
+ }
+
+ // This thread runs while listening for incoming connections. It behaves
+ // like a server-side client. It runs until a connection is accepted
+ // (or until cancelled)
+ private class AcceptThread extends Thread {
+ // The local server socket
+ private BluetoothServerSocket mmServerSocket;
+ private String mSocketType;
+ boolean isRunning = true;
+
+ public AcceptThread(boolean isAndroid) {
+ BluetoothServerSocket tmp = null;
+
+ // Create a new listening server socket
+ try {
+ if(isAndroid)
+ tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, UUID_ANDROID_DEVICE);
+ else
+ tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, UUID_OTHER_DEVICE);
+ } catch (IOException e) { }
+ mmServerSocket = tmp;
+ }
+
+ public void run() {
+ setName("AcceptThread" + mSocketType);
+ BluetoothSocket socket = null;
+
+ // Listen to the server socket if we're not connected
+ while (mState != BluetoothState.STATE_CONNECTED && isRunning) {
+ try {
+ // This is a blocking call and will only return on a
+ // successful connection or an exception
+ socket = mmServerSocket.accept();
+ } catch (IOException e) {
+ break;
+ }
+
+ // If a connection was accepted
+ if (socket != null) {
+ synchronized (BluetoothService.this) {
+ switch (mState) {
+ case BluetoothState.STATE_LISTEN:
+ case BluetoothState.STATE_CONNECTING:
+ // Situation normal. Start the connected thread.
+ connected(socket, socket.getRemoteDevice(),
+ mSocketType);
+ break;
+ case BluetoothState.STATE_NONE:
+ case BluetoothState.STATE_CONNECTED:
+ // Either not ready or already connected. Terminate new socket.
+ try {
+ socket.close();
+ } catch (IOException e) { }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ public void cancel() {
+ try {
+ mmServerSocket.close();
+ mmServerSocket = null;
+ } catch (IOException e) { }
+ }
+
+ public void kill() {
+ isRunning = false;
+ }
+ }
+
+
+ // This thread runs while attempting to make an outgoing connection
+ // with a device. It runs straight through
+ // the connection either succeeds or fails
+ private class ConnectThread extends Thread {
+ private final BluetoothSocket mmSocket;
+ private final BluetoothDevice mmDevice;
+ private String mSocketType;
+
+ public ConnectThread(BluetoothDevice device) {
+ mmDevice = device;
+ BluetoothSocket tmp = null;
+
+ // Get a BluetoothSocket for a connection with the
+ // given BluetoothDevice
+ try {
+ if(BluetoothService.this.isAndroid)
+ tmp = device.createRfcommSocketToServiceRecord(UUID_ANDROID_DEVICE);
+ else
+ tmp = device.createRfcommSocketToServiceRecord(UUID_OTHER_DEVICE);
+ } catch (IOException e) { }
+ mmSocket = tmp;
+ }
+
+ public void run() {
+ // Always cancel discovery because it will slow down a connection
+ mAdapter.cancelDiscovery();
+
+ // Make a connection to the BluetoothSocket
+ try {
+ // This is a blocking call and will only return on a
+ // successful connection or an exception
+ mmSocket.connect();
+ } catch (IOException e) {
+ // Close the socket
+ try {
+ mmSocket.close();
+ } catch (IOException e2) { }
+ connectionFailed();
+ return;
+ }
+
+ // Reset the ConnectThread because we're done
+ synchronized (BluetoothService.this) {
+ mConnectThread = null;
+ }
+
+ // Start the connected thread
+ connected(mmSocket, mmDevice, mSocketType);
+ }
+
+ public void cancel() {
+ try {
+ mmSocket.close();
+ } catch (IOException e) { }
+ }
+ }
+
+ // This thread runs during a connection with a remote device.
+ // It handles all incoming and outgoing transmissions.
+ private class ConnectedThread extends Thread {
+ private final BluetoothSocket mmSocket;
+ private final InputStream mmInStream;
+ private final OutputStream mmOutStream;
+
+ public ConnectedThread(BluetoothSocket socket, String socketType) {
+ mmSocket = socket;
+ InputStream tmpIn = null;
+ OutputStream tmpOut = null;
+
+ // Get the BluetoothSocket input and output streams
+ try {
+ tmpIn = socket.getInputStream();
+ tmpOut = socket.getOutputStream();
+ } catch (IOException e) { }
+
+ mmInStream = tmpIn;
+ mmOutStream = tmpOut;
+ }
+
+ public void run() {
+ byte[] buffer;
+ ArrayList arr_byte = new ArrayList();
+
+ // Keep listening to the InputStream while connected
+ while (true) {
+ try {
+ int data = mmInStream.read();
+ if(data == 0x0A) {
+ } else if(data == 0x0D) {
+ buffer = new byte[arr_byte.size()];
+ for(int i = 0 ; i < arr_byte.size() ; i++) {
+ buffer[i] = arr_byte.get(i).byteValue();
+ }
+ // Send the obtained bytes to the UI Activity
+ mHandler.obtainMessage(BluetoothState.MESSAGE_READ
+ , buffer.length, -1, buffer).sendToTarget();
+ arr_byte = new ArrayList();
+ } else {
+ arr_byte.add(data);
+ }
+ } catch (IOException e) {
+ connectionLost();
+ // Start the service over to restart listening mode
+ BluetoothService.this.start(BluetoothService.this.isAndroid);
+ break;
+ }
+ }
+ }
+
+ // Write to the connected OutStream.
+ // @param buffer The bytes to write
+ public void write(byte[] buffer) {
+ try {/*
+ byte[] buffer2 = new byte[buffer.length + 2];
+ for(int i = 0 ; i < buffer.length ; i++)
+ buffer2[i] = buffer[i];
+ buffer2[buffer2.length - 2] = 0x0A;
+ buffer2[buffer2.length - 1] = 0x0D;*/
+ mmOutStream.write(buffer);
+ // Share the sent message back to the UI Activity
+ mHandler.obtainMessage(BluetoothState.MESSAGE_WRITE
+ , -1, -1, buffer).sendToTarget();
+ } catch (IOException e) { }
+ }
+
+ public void cancel() {
+ try {
+ mmSocket.close();
+ } catch (IOException e) { }
+ }
+ }
+}
\ No newline at end of file
diff --git a/library/src/main/java/app/akexorcist/bluetotohspp/library/BluetoothState.java b/library/src/main/java/app/akexorcist/bluetotohspp/library/BluetoothState.java
new file mode 100644
index 0000000..67ab12b
--- /dev/null
+++ b/library/src/main/java/app/akexorcist/bluetotohspp/library/BluetoothState.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014 Akexorcist
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package app.akexorcist.bluetotohspp.library;
+
+public class BluetoothState {
+ // Constants that indicate the current connection state
+ public static final int STATE_NONE = 0; // we're doing nothing
+ public static final int STATE_LISTEN = 1; // now listening for incoming connections
+ public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
+ public static final int STATE_CONNECTED = 3; // now connected to a remote device
+ public static final int STATE_NULL = -1; // now service is null
+
+ // Message types sent from the BluetoothChatService Handler
+ public static final int MESSAGE_STATE_CHANGE = 1;
+ public static final int MESSAGE_READ = 2;
+ public static final int MESSAGE_WRITE = 3;
+ public static final int MESSAGE_DEVICE_NAME = 4;
+ public static final int MESSAGE_TOAST = 5;
+
+ // Intent request codes
+ public static final int REQUEST_CONNECT_DEVICE = 384;
+ public static final int REQUEST_ENABLE_BT = 385;
+
+ // Key names received from the BluetoothChatService Handler
+ public static final String DEVICE_NAME = "device_name";
+ public static final String DEVICE_ADDRESS = "device_address";
+ public static final String TOAST = "toast";
+
+ public static final boolean DEVICE_ANDROID = true;
+ public static final boolean DEVICE_OTHER = false;
+
+ // Return Intent extra
+ public static String EXTRA_DEVICE_ADDRESS = "device_address";
+
+}
diff --git a/library/src/main/java/app/akexorcist/bluetotohspp/library/DeviceList.java b/library/src/main/java/app/akexorcist/bluetotohspp/library/DeviceList.java
new file mode 100644
index 0000000..246ce2f
--- /dev/null
+++ b/library/src/main/java/app/akexorcist/bluetotohspp/library/DeviceList.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2014 Akexorcist
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package app.akexorcist.bluetotohspp.library;
+
+import java.util.Set;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.AdapterView.OnItemClickListener;
+
+@SuppressLint("NewApi")
+public class DeviceList extends Activity {
+ // Debugging
+ private static final String TAG = "BluetoothSPP";
+ private static final boolean D = true;
+
+ // Member fields
+ private BluetoothAdapter mBtAdapter;
+ private ArrayAdapter mPairedDevicesArrayAdapter;
+ private Set pairedDevices;
+ private Button scanButton;
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Setup the window
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ int listId = getIntent().getIntExtra("layout_list", R.layout.device_list);
+ setContentView(listId);
+
+ String strBluetoothDevices = getIntent().getStringExtra("bluetooth_devices");
+ if(strBluetoothDevices == null)
+ strBluetoothDevices = "Bluetooth Devices";
+ setTitle(strBluetoothDevices);
+
+ // Set result CANCELED in case the user backs out
+ setResult(Activity.RESULT_CANCELED);
+
+ // Initialize the button to perform device discovery
+ scanButton = (Button) findViewById(R.id.button_scan);
+ String strScanDevice = getIntent().getStringExtra("scan_for_devices");
+ if(strScanDevice == null)
+ strScanDevice = "SCAN FOR DEVICES";
+ scanButton.setText(strScanDevice);
+ scanButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ doDiscovery();
+ }
+ });
+
+ // Initialize array adapters. One for already paired devices
+ // and one for newly discovered devices
+ int layout_text = getIntent().getIntExtra("layout_text", R.layout.device_name);
+ mPairedDevicesArrayAdapter = new ArrayAdapter(this, layout_text);
+
+ // Find and set up the ListView for paired devices
+ ListView pairedListView = (ListView) findViewById(R.id.list_devices);
+ pairedListView.setAdapter(mPairedDevicesArrayAdapter);
+ pairedListView.setOnItemClickListener(mDeviceClickListener);
+
+ // Register for broadcasts when a device is discovered
+ IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
+ this.registerReceiver(mReceiver, filter);
+
+ // Register for broadcasts when discovery has finished
+ filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
+ this.registerReceiver(mReceiver, filter);
+
+ // Get the local Bluetooth adapter
+ mBtAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ // Get a set of currently paired devices
+ pairedDevices = mBtAdapter.getBondedDevices();
+
+ // If there are paired devices, add each one to the ArrayAdapter
+ if (pairedDevices.size() > 0) {
+ for (BluetoothDevice device : pairedDevices) {
+ mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
+ }
+ } else {
+ String noDevices = "No devices found";
+ mPairedDevicesArrayAdapter.add(noDevices);
+ }
+ }
+
+ protected void onDestroy() {
+ super.onDestroy();
+ // Make sure we're not doing discovery anymore
+ if (mBtAdapter != null) {
+ mBtAdapter.cancelDiscovery();
+ }
+
+ // Unregister broadcast listeners
+ this.unregisterReceiver(mReceiver);
+ this.finish();
+ }
+
+ // Start device discover with the BluetoothAdapter
+ private void doDiscovery() {
+ if (D) Log.d(TAG, "doDiscovery()");
+
+ // Remove all element from the list
+ mPairedDevicesArrayAdapter.clear();
+
+ // If there are paired devices, add each one to the ArrayAdapter
+ if (pairedDevices.size() > 0) {
+ for (BluetoothDevice device : pairedDevices) {
+ mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
+ }
+ } else {
+ String strNoFound = getIntent().getStringExtra("no_devices_found");
+ if(strNoFound == null)
+ strNoFound = "No devices found";
+ mPairedDevicesArrayAdapter.add(strNoFound);
+ }
+
+ // Indicate scanning in the title
+ String strScanning = getIntent().getStringExtra("scanning");
+ if(strScanning == null)
+ strScanning = "Scanning for devices...";
+ setProgressBarIndeterminateVisibility(true);
+ setTitle(strScanning);
+
+ // Turn on sub-title for new devices
+ // findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
+ // If we're already discovering, stop it
+ if (mBtAdapter.isDiscovering()) {
+ mBtAdapter.cancelDiscovery();
+ }
+
+ // Request discover from BluetoothAdapter
+ mBtAdapter.startDiscovery();
+ }
+
+ // The on-click listener for all devices in the ListViews
+ private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
+ public void onItemClick(AdapterView> av, View v, int arg2, long arg3) {
+ // Cancel discovery because it's costly and we're about to connect
+ if(mBtAdapter.isDiscovering())
+ mBtAdapter.cancelDiscovery();
+
+ String strNoFound = getIntent().getStringExtra("no_devices_found");
+ if(strNoFound == null)
+ strNoFound = "No devices found";
+ if(!((TextView) v).getText().toString().equals(strNoFound)) {
+ // Get the device MAC address, which is the last 17 chars in the View
+ String info = ((TextView) v).getText().toString();
+ String address = info.substring(info.length() - 17);
+
+ // Create the result Intent and include the MAC address
+ Intent intent = new Intent();
+ intent.putExtra(BluetoothState.EXTRA_DEVICE_ADDRESS, address);
+
+ // Set result and finish this Activity
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+ }
+ };
+
+ // The BroadcastReceiver that listens for discovered devices and
+ // changes the title when discovery is finished
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ // When discovery finds a device
+ if (BluetoothDevice.ACTION_FOUND.equals(action)) {
+ // Get the BluetoothDevice object from the Intent
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+
+ // If it's already paired, skip it, because it's been listed already
+ if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
+ String strNoFound = getIntent().getStringExtra("no_devices_found");
+ if(strNoFound == null)
+ strNoFound = "No devices found";
+
+ if(mPairedDevicesArrayAdapter.getItem(0).equals(strNoFound)) {
+ mPairedDevicesArrayAdapter.remove(strNoFound);
+ }
+ mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
+ }
+
+ // When discovery is finished, change the Activity title
+ } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
+ setProgressBarIndeterminateVisibility(false);
+ String strSelectDevice = getIntent().getStringExtra("select_device");
+ if(strSelectDevice == null)
+ strSelectDevice = "Select a device to connect";
+ setTitle(strSelectDevice);
+ }
+ }
+ };
+
+}
diff --git a/library/src/main/res/layout/device_list.xml b/library/src/main/res/layout/device_list.xml
new file mode 100644
index 0000000..4da30ba
--- /dev/null
+++ b/library/src/main/res/layout/device_list.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
diff --git a/library/src/main/res/layout/device_name.xml b/library/src/main/res/layout/device_name.xml
new file mode 100644
index 0000000..8953073
--- /dev/null
+++ b/library/src/main/res/layout/device_name.xml
@@ -0,0 +1,23 @@
+
+
+
diff --git a/library/src/main/res/values-sw600dp/dimens.xml b/library/src/main/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..2c59c35
--- /dev/null
+++ b/library/src/main/res/values-sw600dp/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 25sp
+ 10dp
+
+
diff --git a/library/src/main/res/values-sw720dp-land/dimens.xml b/library/src/main/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..e8ab223
--- /dev/null
+++ b/library/src/main/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 30sp
+ 15dp
+
+
diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..3094132
--- /dev/null
+++ b/library/src/main/res/values/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 18sp
+ 5dp
+
+
diff --git a/settings.gradle b/settings.gradle
index e7b4def..620e18e 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1,2 @@
-include ':app'
+include ':app', ':library', ':joystickView'
+